diff --git a/.reuse/dep5 b/.reuse/dep5
index 7f721430d7..82606c2a30 100644
--- a/.reuse/dep5
+++ b/.reuse/dep5
@@ -29,7 +29,7 @@ Copyright: None
License: CC0-1.0
# ignore files
-Files: src/*.json src/*.xml src/*.policy src/*/pinyin.dict src/*.js src/*.ini src/*.qss src/*.theme src/*/templates/* src/*.psd src/*/com.deepin.filemanager.daemon.conf src/dfm-base/qrc/configure/*.cpp examples/* src/services/*.conf
+Files: src/*.json src/*.xml src/*.policy src/*/pinyin.dict src/*.js src/*.ini src/*.qss src/*.theme src/*/templates/* src/*.psd src/*/com.deepin.filemanager.daemon.conf src/dfm-base/qrc/configure/*.cpp examples/* src/services/*.conf src/services/*.pkla
Copyright: None
License: CC0-1.0
diff --git a/assets/configs/org.deepin.dde.file-manager.diskencrypt.json b/assets/configs/org.deepin.dde.file-manager.diskencrypt.json
new file mode 100644
index 0000000000..bbb47cc4f6
--- /dev/null
+++ b/assets/configs/org.deepin.dde.file-manager.diskencrypt.json
@@ -0,0 +1,40 @@
+{
+ "magic":"dsg.config.meta",
+ "version":"1.0",
+ "contents":{
+ "allowExportEncKey":{
+ "value": true,
+ "serial":0,
+ "flags":["global"],
+ "name":"Allow export the encrypt key",
+ "name[zh_CN]":"允许导出加密密钥",
+ "description[zh_CN]":"用于控制是否显示加密密钥导出窗口",
+ "description":"It's used to control whether or not the encryption key export window is displayed",
+ "permissions":"readwrite",
+ "visibility":"public"
+ },
+ "encryptAlgorithm" : {
+ "value": "sm4",
+ "serial":0,
+ "flags":["global"],
+ "name":"Encrypt algorithm",
+ "name[zh_CN]":"加密算法",
+ "description[zh_CN]":"分区加密所使用的默认加密算法",
+ "description":"It's the default algorithm for encrypting partitions",
+ "permissions":"readwrite",
+ "visibility":"public"
+ },
+ "enableEncrypt": {
+ "value": false,
+ "serial":0,
+ "flags":["global"],
+ "name":"Enable partition encrypt",
+ "name[zh_CN]":"启用分区加密",
+ "description[zh_CN]":"用于控制分区加密功能是否在文管启用",
+ "description":"It's used to control whether to enable partition encryption feature in dde-file-manager.",
+ "permissions":"readwrite",
+ "visibility":"public"
+ }
+ }
+}
+
diff --git a/assets/dbus/org.deepin.Filemanager.DiskEncrypt.xml b/assets/dbus/org.deepin.Filemanager.DiskEncrypt.xml
new file mode 100644
index 0000000000..1e430f8fbd
--- /dev/null
+++ b/assets/dbus/org.deepin.Filemanager.DiskEncrypt.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/debian/control b/debian/control
index ae00ec6389..bc990d9a3b 100644
--- a/debian/control
+++ b/debian/control
@@ -62,7 +62,8 @@ Build-Depends:
libdfm6-io-dev,
libdfm6-mount-dev,
libdfm6-burn-dev,
- libxcb-xfixes0-dev (>= 1.10~)
+ libxcb-xfixes0-dev (>= 1.10~),
+ libdeepin-service-framework-dev
Standards-Version: 3.9.8
Homepage: http://www.deepin.org
@@ -74,7 +75,7 @@ Depends:
libdde-file-manager (=${binary:Version}),
libqt6sql6-sqlite,
qt6-translations-l10n,
- libimageeditor6
+ libimageeditor6 | hello
Conflicts: dde-workspace (<< 2.90.5), dde-file-manager-oem, dde-desktop-plugins
Replaces: dde-file-manager-oem, dde-file-manager (<< 6.0.1), dde-desktop-plugins
Recommends: qt5dxcb-plugin, deepin-screensaver, dcc-wallpapersetting-plugin
@@ -97,18 +98,24 @@ Depends:
dde-file-manager-services-plugins (=${binary:Version}),
qml6-module-qtquick-controls,
qml6-module-qtquick-layouts,
- qml6-module-qtquick-window
+ qml6-module-qtquick-window,
+ tpm2-abrmd,
+ libtss2-tcti-pcap0,
+ libtss2-tcti-tabrmd0,
+ libusec-recoverykey | hello
Replaces: dde-file-manager-oem, dde-desktop (<< 6.0.1),
dde-file-manager-preview,
dde-file-manager-preview-plugins,
dde-file-manager-plugins,
dde-file-manager-daemon-plugins,
- dde-file-manager-common-plugins
+ dde-file-manager-common-plugins,
+ dfmplugin-disk-encrypt
Conflicts: dde-file-manager-preview,
dde-file-manager-preview-plugins,
dde-file-manager-plugins,
dde-file-manager-daemon-plugins,
- dde-file-manager-common-plugins
+ dde-file-manager-common-plugins,
+ dfmplugin-disk-encrypt
Recommends: dde-qt5integration, avfs, samba, deepin-anything-server
Description: File manager front end
File manager front-end of Deepin OS
@@ -143,6 +150,7 @@ Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: deepin desktop-environment - deepin-service-manager plugins module
Deepin Desktop Environment (DDE) - deepin-service-manager plugins module.
+Replaces: dfmplugin-disk-encrypt
Package: libdfm-extension-dev
Architecture: any
diff --git a/debian/dde-file-manager-services-plugins.install b/debian/dde-file-manager-services-plugins.install
index 7cc95595cc..38d7eca9ef 100644
--- a/debian/dde-file-manager-services-plugins.install
+++ b/debian/dde-file-manager-services-plugins.install
@@ -1,6 +1,9 @@
usr/lib/*/deepin-service-manager/*.so
usr/share/deepin-service-manager/system/*.json
usr/share/deepin-service-manager/user/*.json
+usr/share/deepin-service-manager/other/*.json
usr/share/dbus-1/system.d/*.conf
usr/share/dbus-1/system-services/*.service
-etc/systemd/system/deepin-service-group@.service.d/*
\ No newline at end of file
+usr/share/dbus-1/system.d/org.deepin.filemanager.diskencrypt.conf
+etc/systemd/system/deepin-service-group@.service.d/*
+etc/polkit-1/localauthority/10-vendor.d/99-dde-file-manager-encrypt.pkla
\ No newline at end of file
diff --git a/debian/dde-file-manager.install b/debian/dde-file-manager.install
index 618f3edc3b..538b58e607 100644
--- a/debian/dde-file-manager.install
+++ b/debian/dde-file-manager.install
@@ -8,6 +8,7 @@ usr/bin/dde-property-dialog
usr/bin/dde-file-dialog
usr/bin/dde-select-dialog-x11
usr/bin/dde-select-dialog-wayland
+usr/bin/deepin-diskencrypt-service
usr/lib/*/dde-file-manager/plugins/filemanager-core/*.so
usr/lib/*/dde-file-manager/plugins/previews/*.so
usr/share/applications/dde-file-manager.desktop
diff --git a/examples/dfmplugin-encrypt-manager-demo/CMakeLists.txt b/examples/dfmplugin-encrypt-manager-demo/CMakeLists.txt
new file mode 100644
index 0000000000..8f17eb4859
--- /dev/null
+++ b/examples/dfmplugin-encrypt-manager-demo/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(encryptManagerDemo)
+
+find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
+find_package(dfm-framework REQUIRED)
+find_package(Dtk COMPONENTS Widget REQUIRED)
+
+file(GLOB_RECURSE SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
+
+add_executable(${PROJECT_NAME} ${SRC})
+
+target_link_libraries(${PROJECT_NAME}
+ Qt5::Core
+ Qt5::Widgets
+ ${dfm-framework_LIBRARIES}
+ ${DtkWidget_LIBRARIES}
+ )
diff --git a/examples/dfmplugin-encrypt-manager-demo/main.cpp b/examples/dfmplugin-encrypt-manager-demo/main.cpp
new file mode 100644
index 0000000000..ddb3756df4
--- /dev/null
+++ b/examples/dfmplugin-encrypt-manager-demo/main.cpp
@@ -0,0 +1,49 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "mainwindow.h"
+
+#include
+#include
+
+#include
+
+inline constexpr char kPluginIID[] { "org.deepin.plugin.filemanager" };
+
+static bool pluginsLoad()
+{
+#ifdef QT_DEBUG
+ QStringList pluginsDirs;
+ pluginsDirs.push_back(PLUGIN_DIR);
+ QStringList blackNames {};
+ DPF_NAMESPACE::LifeCycle::initialize({ kPluginIID }, pluginsDirs, blackNames);
+
+ if (!DPF_NAMESPACE::LifeCycle::readPlugins())
+ return false;
+
+ if (!DPF_NAMESPACE::LifeCycle::loadPlugins())
+ return false;
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ qputenv("QT_LOGGING_RULES", "*.info=true");
+
+ QApplication a(argc, argv);
+
+ if (!pluginsLoad()) {
+ qCritical() << "Load plugin failed!";
+ abort();
+ }
+
+ MainWindow window;
+ window.show();
+
+ return a.exec();
+}
diff --git a/examples/dfmplugin-encrypt-manager-demo/mainwindow.cpp b/examples/dfmplugin-encrypt-manager-demo/mainwindow.cpp
new file mode 100644
index 0000000000..f4b301f315
--- /dev/null
+++ b/examples/dfmplugin-encrypt-manager-demo/mainwindow.cpp
@@ -0,0 +1,616 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "mainwindow.h"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+
+Q_DECLARE_METATYPE(QString *)
+Q_DECLARE_METATYPE(bool *)
+
+DWIDGET_USE_NAMESPACE
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ initUi();
+ initConnect();
+}
+
+void MainWindow::initUi()
+{
+ QWidget *mainWidget = new QWidget(this);
+ QVBoxLayout *mainLay = new QVBoxLayout;
+ mainWidget->setLayout(mainLay);
+
+ editInput = new QLineEdit(mainWidget);
+
+ textBrowser = new QTextBrowser(mainWidget);
+ textBrowser->setReadOnly(true);
+
+ QGridLayout *btnLay = new QGridLayout;
+ btnCheckTpm = new QPushButton(tr("Check TPM"), mainWidget);
+ btnGetRandom = new QPushButton(tr("Get Random"), mainWidget);
+ btnCheckAlgo = new QPushButton(tr("Check Algo"), mainWidget);
+ btnEncrypt = new QPushButton(tr("Encrypt"), mainWidget);
+ btnDecrypt = new QPushButton(tr("Decrypt"), mainWidget);
+ btnEncryptTwo = new QPushButton(tr("EncryptInProcess"), mainWidget);
+ btnDecryptTwo = new QPushButton(tr("DecryptInProcess"), mainWidget);
+ btnEncryptThree = new QPushButton(tr("EncryptByCommand"), mainWidget);
+ btnDecryptThree = new QPushButton(tr("DecryptByCommand"), mainWidget);
+ btnLay->addWidget(btnCheckTpm, 0, 0);
+ btnLay->addWidget(btnGetRandom, 0, 1);
+ btnLay->addWidget(btnCheckAlgo, 0, 2);
+ btnLay->addWidget(btnEncrypt, 1, 0);
+ btnLay->addWidget(btnDecrypt, 1, 1);
+ btnLay->addWidget(btnEncryptTwo, 2, 0);
+ btnLay->addWidget(btnDecryptTwo, 2, 1);
+ btnLay->addWidget(btnEncryptThree, 3, 0);
+ btnLay->addWidget(btnDecryptThree, 3, 1);
+
+ mainLay->addWidget(editInput);
+ mainLay->addWidget(textBrowser);
+ mainLay->addItem(btnLay);
+
+ setCentralWidget(mainWidget);
+ setMinimumSize(800, 500);
+}
+
+void MainWindow::initConnect()
+{
+ connect(btnCheckTpm, &QPushButton::clicked, this, [this] {
+ int result = dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_TPMIsAvailablePro").toInt();
+ if (result == 0)
+ textBrowser->append("TPM is available!");
+ else
+ textBrowser->append("TPM is not available!");
+ });
+ connect(btnGetRandom, &QPushButton::clicked, this, [this] {
+ int size = editInput->text().toInt();
+ QString out;
+ int result = dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_GetRandomByTPMPro", size, &out).toInt();
+ if (result == 0) {
+ textBrowser->append(QString("Random is: %1").arg(out));
+ } else {
+ textBrowser->append("Get random failed!");
+ }
+ });
+ connect(btnCheckAlgo, &QPushButton::clicked, this, [this] {
+ const QString algoName = editInput->text();
+ bool bSupport { false };
+ int result = dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_IsTPMSupportAlgoPro", algoName, &bSupport).toInt();
+ if (result == 0) {
+ textBrowser->append(QString("The check result is %1!").arg(bSupport));
+ } else {
+ textBrowser->append("Check algo name failed!");
+ }
+ });
+ connect(btnEncrypt, &QPushButton::clicked, this, [this] {
+ const QString hashAlgo = "sha256";
+ const QString keyAlgo = "aes";
+ const QString keyPin = ""/*"12345678"*/;
+ const QString password = "Qwer@1234";
+ const QString dirPath = "/home/uos/gongheng/tmpTemp";
+
+ QFutureWatcher watcher;
+ QEventLoop loop;
+ QFuture future = QtConcurrent::run([hashAlgo, keyAlgo, keyPin, password, dirPath] {
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_EncryptByTPM", hashAlgo, keyAlgo, keyPin, password, dirPath).toBool();
+ });
+ connect(&watcher, &QFutureWatcher::finished, this, [&watcher, &loop] {
+ if (watcher.result()) {
+ loop.exit(0);
+ } else {
+ loop.exit(-1);
+ }
+ });
+ watcher.setFuture(future);
+
+ DSpinner spinner(this);
+ spinner.setFixedSize(50, 50);
+ spinner.move((width() - spinner.width()) / 2, (height() - spinner.height()) / 2);
+ spinner.start();
+ spinner.show();
+
+ int re = loop.exec();
+ bool result = re == 0 ? true : false;
+
+ if (result) {
+ textBrowser->append("Encrypt success!");
+ QFile file(dirPath + QDir::separator() + "tpm_encrypt.txt");
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QByteArray ciphertext = file.readAll();
+ QByteArray baseCiphertext = ciphertext.toBase64();
+ textBrowser->append("Cipher text: " + QString(baseCiphertext));
+ file.close();
+ }
+ file.setFileName(dirPath + QDir::separator() + "key.priv");
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QByteArray priKey = file.readAll();
+ QByteArray basePriKey = priKey.toBase64();
+ textBrowser->append("Pri key: " + QString(basePriKey));
+ file.close();
+ }
+
+ file.setFileName(dirPath + QDir::separator() + "key.pub");
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QByteArray pubKey = file.readAll();
+ QByteArray basePubKey = pubKey.toBase64();
+ textBrowser->append("Pub key: " + QString(basePubKey));
+ file.close();
+ }
+
+ } else {
+ textBrowser->append("Encrypt failed!");
+ }
+ });
+ connect(btnDecrypt, &QPushButton::clicked, this, [this] {
+ const QString keyPin = "" /*"12345678"*/;
+ const QString dirPath = "/home/uos/gongheng/tmpTemp";
+ QString password;
+ bool result = dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_DecryptByTPM", keyPin, dirPath, &password).toBool();
+ if (result) {
+ textBrowser->append(QString("Password is: %1 !").arg(password));
+ } else {
+ textBrowser->append("Decrypt failed!");
+ }
+ });
+ connect(btnEncryptTwo, &QPushButton::clicked, this, [this]{
+ const QString &dirPath = QDir::homePath() + "/.TPMKey";
+ QDir dir(dirPath);
+ if (!dir.exists())
+ dir.mkpath(dirPath);
+ QString pwd;
+ int success = dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_GetRandomByTPM", 14, &pwd).toInt();
+ if (success != 0) {
+ textBrowser->append("Create password faild!");
+ return;
+ }
+ // TPM
+// QVariantMap map {
+// { "PropertyKey_EncryptType", 1 },
+// { "PropertyKey_SessionHashAlgo", "sha256" },
+// { "PropertyKey_SessionKeyAlgo", "aes" },
+// { "PropertyKey_PrimaryHashAlgo", "sha256" },
+// { "PropertyKey_PrimaryKeyAlgo", "rsa" },
+// { "PropertyKey_MinorHashAlgo", "sha256" },
+// { "PropertyKey_MinorKeyAlgo", "aes" },
+// { "PropertyKey_DirPath", dirPath },
+// { "PropertyKey_Plain", pwd },
+// { "PropertyKey_Pcr", "7" },
+// { "PropertyKey_PcrBank", "sha256" }
+// };
+// QVariantMap map {
+// { "PropertyKey_EncryptType", 2 },
+// { "PropertyKey_SessionHashAlgo", "sha256" },
+// { "PropertyKey_SessionKeyAlgo", "aes" },
+// { "PropertyKey_PrimaryHashAlgo", "sha256" },
+// { "PropertyKey_PrimaryKeyAlgo", "rsa" },
+// { "PropertyKey_MinorHashAlgo", "sha256" },
+// { "PropertyKey_MinorKeyAlgo", "aes" },
+// { "PropertyKey_DirPath", dirPath },
+// { "PropertyKey_Plain", pwd },
+// { "PropertyKey_PinCode", "pin123456" }
+// };
+ QVariantMap map {
+ { "PropertyKey_EncryptType", 3 },
+ { "PropertyKey_SessionHashAlgo", "sha256" },
+ { "PropertyKey_SessionKeyAlgo", "aes" },
+ { "PropertyKey_PrimaryHashAlgo", "sha256" },
+ { "PropertyKey_PrimaryKeyAlgo", "rsa" },
+ { "PropertyKey_MinorHashAlgo", "sha256" },
+ { "PropertyKey_MinorKeyAlgo", "aes" },
+ { "PropertyKey_DirPath", dirPath },
+ { "PropertyKey_Plain", pwd },
+ { "PropertyKey_Pcr", "7" },
+ { "PropertyKey_PcrBank", "sha256" },
+ { "PropertyKey_PinCode", "pin123456" }
+ };
+ // TCM
+// QVariantMap map {
+// { "PropertyKey_EncryptType", 1 },
+// { "PropertyKey_SessionHashAlgo", "sm3_256" },
+// { "PropertyKey_SessionKeyAlgo", "sm4" },
+// { "PropertyKey_PrimaryHashAlgo", "sm3_256" },
+// { "PropertyKey_PrimaryKeyAlgo", "sm4" },
+// { "PropertyKey_MinorHashAlgo", "sm3_256" },
+// { "PropertyKey_MinorKeyAlgo", "sm4" },
+// { "PropertyKey_DirPath", dirPath },
+// { "PropertyKey_Plain", pwd },
+// { "PropertyKey_Pcr", "7" },
+// { "PropertyKey_PcrBank", "sm3_256" }
+// };
+// QVariantMap map {
+// { "PropertyKey_EncryptType", 2 },
+// { "PropertyKey_SessionHashAlgo", "sm3_256" },
+// { "PropertyKey_SessionKeyAlgo", "sm4" },
+// { "PropertyKey_PrimaryHashAlgo", "sm3_256" },
+// { "PropertyKey_PrimaryKeyAlgo", "sm4" },
+// { "PropertyKey_MinorHashAlgo", "sm3_256" },
+// { "PropertyKey_MinorKeyAlgo", "sm4" },
+// { "PropertyKey_DirPath", dirPath },
+// { "PropertyKey_Plain", pwd },
+// { "PropertyKey_PinCode", "pin123456" }
+// };
+// QVariantMap map {
+// { "PropertyKey_EncryptType", 3 },
+// { "PropertyKey_SessionHashAlgo", "sm3_256" },
+// { "PropertyKey_SessionKeyAlgo", "sm4" },
+// { "PropertyKey_PrimaryHashAlgo", "sm3_256" },
+// { "PropertyKey_PrimaryKeyAlgo", "sm4" },
+// { "PropertyKey_MinorHashAlgo", "sm3_256" },
+// { "PropertyKey_MinorKeyAlgo", "sm4" },
+// { "PropertyKey_DirPath", dirPath },
+// { "PropertyKey_Plain", pwd },
+// { "PropertyKey_Pcr", "7" },
+// { "PropertyKey_PcrBank", "sha256" },
+// { "PropertyKey_PinCode", "pin123456" }
+// };
+ QFutureWatcher watcher;
+ QEventLoop loop;
+ QFuture future = QtConcurrent::run([map]{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_EncryptByTPMPro", map).toInt();
+ });
+ connect(&watcher, &QFutureWatcher::finished, this, [&watcher, &loop]{
+ if (watcher.result() == 0) {
+ loop.exit(0);
+ } else {
+ loop.exit(-1);
+ }
+ });
+ watcher.setFuture(future);
+
+ DSpinner spinner(this);
+ spinner.setFixedSize(50, 50);
+ spinner.move((width() - spinner.width())/2, (height() - spinner.height())/2);
+ spinner.start();
+ spinner.show();
+
+ int re = loop.exec();
+ bool result = (re == 0 ? true : false);
+
+ if (result) {
+ textBrowser->append(QString("Encrypt success! password is: %1").arg(pwd));
+ } else {
+ textBrowser->append("Encrypt failed!");
+ }
+ });
+
+ connect(btnDecryptTwo, &QPushButton::clicked, this, [this]{
+ const QString &dirPath = QDir::homePath() + "/.TPMKey";
+ QDir dir(dirPath);
+ if (!dir.exists())
+ dir.mkpath(dirPath);
+ QString pwd;
+ // TPM
+ // QVariantMap map {
+ // { "PropertyKey_EncryptType", 1 },
+ // { "PropertyKey_SessionHashAlgo", "sha256" },
+ // { "PropertyKey_SessionKeyAlgo", "aes" },
+ // { "PropertyKey_PrimaryHashAlgo", "sha256" },
+ // { "PropertyKey_PrimaryKeyAlgo", "rsa" },
+ // { "PropertyKey_DirPath", dirPath },
+ // { "PropertyKey_Pcr", "7" },
+ // { "PropertyKey_PcrBank", "sha256" }
+ // };
+ // QVariantMap map {
+ // { "PropertyKey_EncryptType", 2 },
+ // { "PropertyKey_SessionHashAlgo", "sha256" },
+ // { "PropertyKey_SessionKeyAlgo", "aes" },
+ // { "PropertyKey_PrimaryHashAlgo", "sha256" },
+ // { "PropertyKey_PrimaryKeyAlgo", "rsa" },
+ // { "PropertyKey_DirPath", dirPath },
+ // { "PropertyKey_PinCode", "pin123456" }
+ // };
+ QVariantMap map {
+ { "PropertyKey_EncryptType", 3 },
+ { "PropertyKey_SessionHashAlgo", "sha256" },
+ { "PropertyKey_SessionKeyAlgo", "aes" },
+ { "PropertyKey_PrimaryHashAlgo", "sha256" },
+ { "PropertyKey_PrimaryKeyAlgo", "rsa" },
+ { "PropertyKey_DirPath", dirPath },
+ { "PropertyKey_Pcr", "7" },
+ { "PropertyKey_PcrBank", "sha256" },
+ { "PropertyKey_PinCode", "pin123456" }
+ };
+ // TCM
+ // QVariantMap map {
+ // { "PropertyKey_EncryptType", 1 },
+ // { "PropertyKey_SessionHashAlgo", "sm3_256" },
+ // { "PropertyKey_SessionKeyAlgo", "sm4" },
+ // { "PropertyKey_PrimaryHashAlgo", "sm3_256" },
+ // { "PropertyKey_PrimaryKeyAlgo", "sm4" },
+ // { "PropertyKey_DirPath", dirPath },
+ // { "PropertyKey_Pcr", "7" },
+ // { "PropertyKey_PcrBank", "sm3_256" }
+ // };
+ // QVariantMap map {
+ // { "PropertyKey_EncryptType", 2 },
+ // { "PropertyKey_SessionHashAlgo", "sm3_256" },
+ // { "PropertyKey_SessionKeyAlgo", "sm4" },
+ // { "PropertyKey_PrimaryHashAlgo", "sm3_256" },
+ // { "PropertyKey_PrimaryKeyAlgo", "sm4" },
+ // { "PropertyKey_DirPath", dirPath },
+ // { "PropertyKey_PinCode", "pin123456" }
+ // };
+ // QVariantMap map {
+ // { "PropertyKey_EncryptType", 3 },
+ // { "PropertyKey_SessionHashAlgo", "sm3_256" },
+ // { "PropertyKey_SessionKeyAlgo", "sm4" },
+ // { "PropertyKey_PrimaryHashAlgo", "sm3_256" },
+ // { "PropertyKey_PrimaryKeyAlgo", "sm4" },
+ // { "PropertyKey_DirPath", dirPath },
+ // { "PropertyKey_Pcr", "7" },
+ // { "PropertyKey_PcrBank", "sm3_256" },
+ // { "PropertyKey_PinCode", "pin123456" }
+ // };
+ QFutureWatcher watcher;
+ QEventLoop loop;
+ QFuture future = QtConcurrent::run([map, &pwd]{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_DecryptByTPMPro", map, &pwd).toInt();
+ });
+ connect(&watcher, &QFutureWatcher::finished, this, [&watcher, &loop]{
+ if (watcher.result() == 0) {
+ loop.exit(0);
+ } else {
+ loop.exit(-1);
+ }
+ });
+ watcher.setFuture(future);
+
+ DSpinner spinner(this);
+ spinner.setFixedSize(50, 50);
+ spinner.move((width() - spinner.width())/2, (height() - spinner.height())/2);
+ spinner.start();
+ spinner.show();
+
+ int re = loop.exec();
+ bool result = (re == 0 ? true : false);
+
+ if (result) {
+ textBrowser->append(QString("Decrypt success! password is: %1").arg(pwd));
+ } else {
+ textBrowser->append("Decrypt failed!");
+ }
+ });
+
+ connect(btnEncryptThree, &QPushButton::clicked, this, [this] {
+
+ int nType = 2; // 0:kTpmAndPcr 1:kTpmAndPin 2:kTpmAndPinAndPcr
+ const std::string plain = "Qwer@1234";
+
+ const std::string pinCode = "pin123456";
+
+ const std::string pcr = "7";
+ const std::string pcr_bank = "sha256";
+
+ const std::string session_key_alg = "aes";
+ const std::string session_hash_alg = "sha256";
+ const std::string primary_key_alg = "rsa";
+ const std::string primary_hash_alg = "sha256";
+ const std::string minor_key_alg = "aes";
+ const std::string minor_hash_alg = "sha256";
+
+ const QString &dirPath = QDir::homePath() + "/.TPMKey";
+ QDir dir(dirPath);
+ if (!dir.exists())
+ dir.mkpath(dirPath);
+ const std::string basePath = dirPath.toStdString();
+
+ const std::string plainPath = basePath + "/plain.dat";
+ const std::string ivPath = basePath + "/iv.bin";
+
+ const std::string sessionPath = basePath + "/session.dat";
+ const std::string policyPath = basePath + "/policy.dat";
+ const std::string primaryCtxPath = basePath + "/primary.ctx";
+ const std::string pubKeyPath = basePath + "/key.pub";
+ const std::string priKeyPath = basePath + "/key.priv";
+ const std::string keyNamePath = basePath + "/key.name";
+ const std::string keyCtxPath = basePath + "/key.ctx";
+ const std::string cipherPath = basePath + "/cipher.out";
+
+ const std::string pcrPath = basePath + "/pcr_val.bin";
+
+ // generate plain & iv
+ if (std::system(("echo " + plain + " > " + plainPath).c_str()))
+ return false;
+ if (std::system(("tpm2_getrandom -o " + ivPath + " 16").c_str()))
+ return false;
+
+ // set policy
+ if (std::system(("tpm2_startauthsession -S " + sessionPath + " -g " + session_hash_alg + " -G " + session_key_alg).c_str()))
+ return false;
+ if (nType == 0) {
+ if (std::system(("tpm2_pcrread " + pcr_bank + ":" + pcr + " -o " + pcrPath).c_str()))
+ return false;
+ if (std::system(("tpm2_policypcr -S " + sessionPath + " -l " + pcr_bank + ":" + pcr + " -L " + policyPath + " -f " + pcrPath).c_str()))
+ return false;
+ } else if (nType == 1) {
+ if (std::system(("tpm2_policypassword -S " + sessionPath + " -L " + policyPath).c_str()))
+ return false;
+ } else if (nType == 2) {
+ if (std::system(("tpm2_pcrread " + pcr_bank + ":" + pcr + " -o " + pcrPath).c_str()))
+ return false;
+ if (std::system(("tpm2_policypcr -S " + sessionPath + " -l " + pcr_bank + ":" + pcr + " -L " + policyPath + " -f " + pcrPath).c_str()))
+ return false;
+ if (std::system(("tpm2_policypassword -S " + sessionPath + " -L " + policyPath).c_str()))
+ return false;
+ } else {
+ qCritical() << "Tpm type unkonw!";
+ return false;
+ }
+ if (std::system(("tpm2_flushcontext " + sessionPath).c_str()))
+ return false;
+
+ // generate keys
+ if (std::system(("tpm2_createprimary -C o -g " + primary_hash_alg + " -G " + primary_key_alg + " -c " + primaryCtxPath).c_str()))
+ return false;
+ if (nType == 0) {
+ if (std::system(("tpm2_create -g " + minor_hash_alg + " -G " + minor_key_alg + " -u " + pubKeyPath + " -r " + priKeyPath + " -C " + primaryCtxPath + " -L " + policyPath).c_str()))
+ return false;
+ } else if (nType == 1) {
+ if (std::system(("tpm2_create -g " + minor_hash_alg + " -G " + minor_key_alg + " -u " + pubKeyPath + " -r " + priKeyPath + " -C " + primaryCtxPath + " -L " + policyPath + " -p " + pinCode).c_str()))
+ return false;
+ } else if (nType == 2) {
+ if (std::system(("tpm2_create -g " + minor_hash_alg + " -G " + minor_key_alg + " -u " + pubKeyPath + " -r " + priKeyPath + " -C " + primaryCtxPath + " -L " + policyPath + " -p " + pinCode).c_str()))
+ return false;
+ } else {
+ qCritical() << "Tpm type unkonw!";
+ return false;
+ }
+
+ if (std::system(("tpm2_load -C " + primaryCtxPath + " -u " + pubKeyPath + " -r " + priKeyPath + " -n " + keyNamePath + " -c " + keyCtxPath).c_str()))
+ return false;
+
+ // generate cipher
+ if (std::system(("tpm2_startauthsession --policy-session -S " + sessionPath + " -g " + session_hash_alg + " -G " + session_key_alg).c_str()))
+ return false;
+ if (nType == 0) {
+ if (std::system(("tpm2_pcrread " + pcr_bank + ":" + pcr + " -o " + pcrPath).c_str()))
+ return false;
+ if (std::system(("tpm2_policypcr -S " + sessionPath + " -l " + pcr_bank + ":" + pcr + " -f " + pcrPath).c_str()))
+ return false;
+ if (std::system(("tpm2_encryptdecrypt -Q --iv " + ivPath + " -c " + keyCtxPath + " -o " + cipherPath + " " + plainPath + " -p session:" + sessionPath).c_str()))
+ return false;
+ } else if (nType == 1) {
+ if (std::system(("tpm2_policypassword -S " + sessionPath + " -L " + policyPath).c_str()))
+ return false;
+ if (std::system(("tpm2_encryptdecrypt -Q --iv " + ivPath + " -c " + keyCtxPath + " -o " + cipherPath + " " + plainPath + " -p session:" + sessionPath + "+" + pinCode).c_str()))
+ return false;
+ } else if (nType == 2) {
+ if (std::system(("tpm2_pcrread " + pcr_bank + ":" + pcr + " -o " + pcrPath).c_str()))
+ return false;
+ if (std::system(("tpm2_policypcr -S " + sessionPath + " -l " + pcr_bank + ":" + pcr + " -f " + pcrPath).c_str()))
+ return false;
+ if (std::system(("tpm2_policypassword -S " + sessionPath + " -L " + policyPath).c_str()))
+ return false;
+ if (std::system(("tpm2_encryptdecrypt -Q --iv " + ivPath + " -c " + keyCtxPath + " -o " + cipherPath + " " + plainPath + " -p session:" + sessionPath + "+" + pinCode).c_str()))
+ return false;
+ } else {
+ qCritical() << "Tpm type unkonw!";
+ return false;
+ }
+ if (std::system(("tpm2_flushcontext " + sessionPath).c_str()))
+ return false;
+
+ // clean files
+ if (nType == 0) {
+ if (std::system(("rm " + keyCtxPath + " " + keyNamePath + " " + plainPath + " " + policyPath + " " + primaryCtxPath + " " + sessionPath + " " + pcrPath).c_str()))
+ return false;
+ } else if (nType == 1) {
+ if (std::system(("rm " + keyCtxPath + " " + keyNamePath + " " + plainPath + " " + policyPath + " " + primaryCtxPath + " " + sessionPath).c_str()))
+ return false;
+ } else if (nType == 2) {
+ if (std::system(("rm " + keyCtxPath + " " + keyNamePath + " " + plainPath + " " + policyPath + " " + primaryCtxPath + " " + sessionPath + " " + pcrPath).c_str()))
+ return false;
+ } else {
+ qCritical() << "Tpm type unkonw!";
+ return false;
+ }
+
+ textBrowser->append(QString("Encrypt success! password is: %1").arg(QString::fromStdString(plain)));
+ return true;
+ });
+
+ connect(btnDecryptThree, &QPushButton::clicked, this, [this] {
+ int nType = 2; // 0:kTpmAndPcr 1:kTpmAndPin 2:kTpmAndPcrAndPin
+ const std::string pinCode = "pin123456";
+ std::string pcr = "7";
+ std::string pcr_bank = "sha256";
+
+ const std::string session_key_alg = "aes";
+ const std::string session_hash_alg = "sha256";
+ const std::string primary_key_alg = "rsa";
+ const std::string primary_hash_alg = "sha256";
+
+ const QString &dirPath = QDir::homePath() + "/.TPMKey";
+ QDir dir(dirPath);
+ if (!dir.exists())
+ dir.mkpath(dirPath);
+ const std::string basePath = dirPath.toStdString();
+
+ const std::string cipherPath = basePath + "/cipher.out";
+ const std::string ivPath = basePath + "/iv.bin";
+ const std::string pubKeyPath = basePath + "/key.pub";
+ const std::string priKeyPath = basePath + "/key.priv";
+
+ const std::string sessionPath = basePath + "/session.dat";
+ const std::string policyPath = basePath + "/policy.dat";
+ const std::string primaryCtxPath = basePath + "/primary.ctx";
+ const std::string keyNamePath = basePath + "/key.name";
+ const std::string keyCtxPath = basePath + "/key.ctx";
+ const std::string clearPath = basePath + "/clear.out";
+
+ if (std::system(("tpm2_startauthsession --policy-session -S " + sessionPath + " -g " + session_hash_alg + " -G " + session_key_alg).c_str()))
+ return false;
+ if (nType == 0) {
+ if (std::system(("tpm2_policypcr -S " + sessionPath + " -l " + pcr_bank + ":" + pcr).c_str()))
+ return false;
+ } else if (nType == 1) {
+ if (std::system(("tpm2_policypassword -S " + sessionPath + " -L " + policyPath).c_str()))
+ return false;
+ } else if (nType == 2) {
+ if (std::system(("tpm2_policypcr -S " + sessionPath + " -l " + pcr_bank + ":" + pcr).c_str()))
+ return false;
+ if (std::system(("tpm2_policypassword -S " + sessionPath + " -L " + policyPath).c_str()))
+ return false;
+ } else {
+ qCritical() << "Tpm type unkonw!";
+ return false;
+ }
+ if (std::system(("tpm2_createprimary -C o -g " + primary_hash_alg + " -G " + primary_key_alg + " -c " + primaryCtxPath).c_str()))
+ return false;
+ if (std::system(("tpm2_load -C " + primaryCtxPath + " -u " + pubKeyPath + " -r " + priKeyPath + " -n " + keyNamePath + " -c " + keyCtxPath).c_str()))
+ return false;
+ if (nType == 0) {
+ if (std::system(("tpm2_encryptdecrypt -Q --iv " + ivPath + " -c " + keyCtxPath + " -d -o " + clearPath + " " + cipherPath + " -p session:" + sessionPath).c_str()))
+ return false;
+ } else if (nType == 1) {
+ if (std::system(("tpm2_encryptdecrypt -Q --iv " + ivPath + " -c " + keyCtxPath + " -d -o " + clearPath + " " + cipherPath + " -p session:" + sessionPath + "+" + pinCode).c_str()))
+ return false;
+ } else if (nType == 2) {
+ if (std::system(("tpm2_encryptdecrypt -Q --iv " + ivPath + " -c " + keyCtxPath + " -d -o " + clearPath + " " + cipherPath + " -p session:" + sessionPath + "+" + pinCode).c_str()))
+ return false;
+ } else {
+ qCritical() << "Tpm type unkonw!";
+ return false;
+ }
+ if (std::system(("tpm2_flushcontext " + sessionPath).c_str()))
+ return false;
+
+ std::ifstream plain_ifs(clearPath, std::ios_base::in);
+ if (!plain_ifs.is_open())
+ return false;
+ std::string plain;
+ plain_ifs >> plain;
+ plain_ifs.close();
+
+ textBrowser->append(QString("Decrypt success! password is: %1").arg(QString::fromStdString(plain)));
+
+ // clean files
+ if (nType == 0) {
+ std::system(("rm " + clearPath + " " + keyCtxPath + " " + keyNamePath + " " + primaryCtxPath + " " + sessionPath).c_str());
+ } else if (nType == 1) {
+ std::system(("rm " + clearPath + " " + keyCtxPath + " " + keyNamePath + " " + policyPath + " " + primaryCtxPath + " " + sessionPath).c_str());
+ } else if (nType == 2) {
+ std::system(("rm " + clearPath + " " + keyCtxPath + " " + keyNamePath + " " + policyPath + " " + primaryCtxPath + " " + sessionPath).c_str());
+ } else {
+ qCritical() << "Tpm type unkonw!";
+ return false;
+ }
+
+ return true;
+ });
+}
diff --git a/examples/dfmplugin-encrypt-manager-demo/mainwindow.h b/examples/dfmplugin-encrypt-manager-demo/mainwindow.h
new file mode 100644
index 0000000000..50b7e023a0
--- /dev/null
+++ b/examples/dfmplugin-encrypt-manager-demo/mainwindow.h
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include
+#include
+#include
+#include
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ explicit MainWindow(QWidget *parent = nullptr);
+
+private:
+ void initUi();
+ void initConnect();
+
+ QLineEdit *editInput { Q_NULLPTR };
+ QTextBrowser *textBrowser { Q_NULLPTR };
+ QPushButton *btnCheckTpm { Q_NULLPTR };
+ QPushButton *btnGetRandom { Q_NULLPTR };
+ QPushButton *btnCheckAlgo { Q_NULLPTR };
+ QPushButton *btnEncrypt { Q_NULLPTR };
+ QPushButton *btnDecrypt { Q_NULLPTR };
+
+ QPushButton *btnEncryptTwo { Q_NULLPTR };
+ QPushButton *btnDecryptTwo { Q_NULLPTR };
+
+ QPushButton *btnEncryptThree { Q_NULLPTR };
+ QPushButton *btnDecryptThree { Q_NULLPTR };
+};
+
+#endif // MAINWINDOW_H
diff --git a/src/apps/dde-file-manager-daemon/main.cpp b/src/apps/dde-file-manager-daemon/main.cpp
index b08920d3d2..ec3fb30242 100644
--- a/src/apps/dde-file-manager-daemon/main.cpp
+++ b/src/apps/dde-file-manager-daemon/main.cpp
@@ -62,7 +62,7 @@ static bool pluginsLoad()
<< QString(DFM_PLUGIN_DAEMON_EDGE_DIR);
#endif
qCInfo(logAppDaemon) << "Using plugins dir:" << pluginsDirs;
- QStringList blackNames { DConfigManager::instance()->value(kPluginsDConfName, "server.blackList").toStringList() };
+ QStringList blackNames { DConfigManager::instance()->value(kPluginsDConfName, "daemon.blackList").toStringList() };
DPF_NAMESPACE::LifeCycle::initialize({ kDaemonInterface }, pluginsDirs, blackNames);
qCInfo(logAppDaemon) << "Depend library paths:" << QCoreApplication::libraryPaths();
diff --git a/src/plugins/filemanager/CMakeLists.txt b/src/plugins/filemanager/CMakeLists.txt
index 8d7b7640dc..9954dfa788 100644
--- a/src/plugins/filemanager/CMakeLists.txt
+++ b/src/plugins/filemanager/CMakeLists.txt
@@ -15,3 +15,5 @@ add_subdirectory(dfmplugin-optical)
add_subdirectory(dfmplugin-myshares)
add_subdirectory(dfmplugin-smbbrowser)
add_subdirectory(dfmplugin-avfsbrowser)
+add_subdirectory(dfmplugin-disk-encrypt-entry)
+add_subdirectory(dfmplugin-encrypt-manager)
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/CMakeLists.txt b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/CMakeLists.txt
new file mode 100644
index 0000000000..cb87095bbd
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/CMakeLists.txt
@@ -0,0 +1,62 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(dfmplugin-disk-encrypt LANGUAGES CXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent)
+
+file(GLOB_RECURSE SRC
+ "${CMAKE_CURRENT_SOURCE_DIR}/*.h"
+ "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/*.json"
+ "${CMAKE_SOURCE_DIR}/src/services/diskencrypt/globaltypesdefine.h"
+)
+
+add_library(${PROJECT_NAME} SHARED
+ ${SRC}
+)
+
+target_link_libraries(${PROJECT_NAME} PRIVATE
+ DFM${DTK_VERSION_MAJOR}::base
+ DFM${DTK_VERSION_MAJOR}::framework
+)
+
+target_compile_definitions(${PROJECT_NAME} PRIVATE DFMPLUGIN_DISK_ENCRYPT_LIBRARY)
+set_target_properties(${PROJECT_NAME} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY ${DFM_BUILD_PLUGIN_FILEMANAGER_DIR})
+
+install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${DFM_PLUGIN_FILEMANAGER_CORE_DIR})
+message(">>>> install ${PROJECT_NAME} into ${DFM_PLUGIN_FILEMANAGER_CORE_DIR}")
+
+execute_process(
+ COMMAND lupdate
+ ./
+ -ts
+ -no-obsolete
+ ${CMAKE_SOURCE_DIR}/translations/disk-encrypt-plugin/disk-encrypt.ts
+ COMMAND lupdate
+ ./
+ -ts
+ -no-obsolete
+ ${CMAKE_SOURCE_DIR}/translations/disk-encrypt-plugin/disk-encrypt_zh_CN.ts
+
+ WORKING_DIRECTORY
+ ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+# 查找匹配 disk-encrypt*.ts 的文件列表
+file(GLOB TS_FILES ${CMAKE_SOURCE_DIR}/translations/disk-encrypt-plugin/disk-encrypt*.ts)
+file(GLOB QM_FILES ${CMAKE_SOURCE_DIR}/translations/disk-encrypt-plugin/disk-encrypt*.qm)
+
+# 添加 lrelease 命令,传递 TS_FILES 列表
+foreach(TS_FILE ${TS_FILES})
+ execute_process(
+ COMMAND lrelease ${TS_FILE}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+endforeach()
+
+install(FILES ${QM_FILES} DESTINATION share/dde-file-manager/translations)
+INSTALL_DCONFIG("org.deepin.dde.file-manager.diskencrypt.json")
+
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/dfmplugin_disk_encrypt_global.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/dfmplugin_disk_encrypt_global.h
new file mode 100644
index 0000000000..a0540cc55d
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/dfmplugin_disk_encrypt_global.h
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef DFMPLUGIN_DISK_ENCRYPT_GLOBAL_H
+#define DFMPLUGIN_DISK_ENCRYPT_GLOBAL_H
+
+#include "services/diskencrypt/globaltypesdefine.h"
+
+#include
+#include
+#include
+
+#if defined(DFMPLUGIN_DISK_ENCRYPT_LIBRARY)
+# define DFMPLUGIN_DISK_ENCRYPT_EXPORT Q_DECL_EXPORT
+#else
+# define DFMPLUGIN_DISK_ENCRYPT_EXPORT Q_DECL_IMPORT
+#endif
+
+enum TPMModuleEncType {
+ kUnknow = 0,
+ kUseTpmAndPcr,
+ kUseTpmAndPin,
+ kUseTpmAndPrcAndPin
+};
+
+inline constexpr char kDaemonBusName[] { "org.deepin.Filemanager.DiskEncrypt" };
+inline constexpr char kDaemonBusPath[] { "/org/deepin/Filemanager/DiskEncrypt" };
+inline constexpr char kDaemonBusIface[] { "org.deepin.Filemanager.DiskEncrypt" };
+
+inline constexpr char kMenuPluginName[] { "dfmplugin_menu" };
+inline constexpr char kComputerMenuSceneName[] { "ComputerMenu" };
+
+inline constexpr int kPasswordSize { 14 };
+inline const QString kGlobalTPMConfigPath("/tmp/dfm-encrypt");
+inline constexpr char kTPMSessionHashAlgo[] { "sha256" };
+inline constexpr char kTPMSessionKeyAlgo[] { "aes" };
+inline constexpr char kTPMPrimaryHashAlgo[] { "sha256" };
+inline constexpr char kTPMPrimaryKeyAlgo[] { "rsa" };
+inline constexpr char kTPMMinorHashAlgo[] { "sha256" };
+inline constexpr char kTPMMinorKeyAlgo[] { "aes" };
+inline constexpr char kTCMSessionHashAlgo[] { "sm3_256" };
+inline constexpr char kTCMSessionKeyAlgo[] { "sm4" };
+inline constexpr char kTCMPrimaryHashAlgo[] { "sm3_256" };
+inline constexpr char kTCMPrimaryKeyAlgo[] { "sm4" };
+inline constexpr char kTCMMinorHashAlgo[] { "sm3_256" };
+inline constexpr char kTCMMinorKeyAlgo[] { "sm4" };
+inline constexpr char kConfigKeySessionHashAlgo[] { "session_hash_algo" };
+inline constexpr char kConfigKeySessionKeyAlgo[] { "session_key_algo" };
+inline constexpr char kConfigKeyPriHashAlgo[] { "primary_hash_algo" };
+inline constexpr char kConfigKeyPriKeyAlgo[] { "primary_key_algo" };
+
+#endif // DFMPLUGIN_DISK_ENCRYPT_GLOBAL_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/diskencryptentry.json b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/diskencryptentry.json
new file mode 100644
index 0000000000..266c2a1bc0
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/diskencryptentry.json
@@ -0,0 +1,15 @@
+{
+ "Name" : "dfmplugin-disk-encrypt",
+ "Version" : "1.0.0",
+ "CompatVersion" : "1.0.0",
+ "Vendor" : "The Uniontech Software Technology Co., Ltd.",
+ "Copyright" : "Copyright (C) 2022 Uniontech Software Technology Co., Ltd.",
+ "License" : [
+ ],
+ "Category" : "",
+ "Description" : "The encrypt plugin for dde-file-manager",
+ "UrlLink" : "https://www.uniontech.com",
+ "Depends" : [
+ "dfmplugin-computer"
+ ]
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/events/eventshandler.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/events/eventshandler.cpp
new file mode 100644
index 0000000000..1cb8d33198
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/events/eventshandler.cpp
@@ -0,0 +1,575 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#include "eventshandler.h"
+#include "dfmplugin_disk_encrypt_global.h"
+#include "gui/encryptprogressdialog.h"
+#include "gui/unlockpartitiondialog.h"
+#include "gui/encryptparamsinputdialog.h"
+#include "utils/encryptutils.h"
+#include "menu/diskencryptmenuscene.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+Q_DECLARE_METATYPE(QString *)
+Q_DECLARE_METATYPE(bool *)
+
+using namespace dfmplugin_diskenc;
+using namespace disk_encrypt;
+DWIDGET_USE_NAMESPACE;
+
+EventsHandler *EventsHandler::instance()
+{
+ static EventsHandler ins;
+ return &ins;
+}
+
+void EventsHandler::bindDaemonSignals()
+{
+ // FIXME(xust) split the unlock module into another plugin.
+ // for unlocking devices in file dialog, this plugin is loaded,
+ // which cause when en/decrypt devices, the signal are handled
+ // by both file manager and file dialog, so multiple progress
+ // dialog and finished dialog are shown.
+ // this class is singleton but in different process it's not.
+ if (qApp->applicationName() != "dde-file-manager")
+ return;
+
+ auto conn = [this](const char *sig, const char *slot) {
+ QDBusConnection::systemBus().connect(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ sig,
+ this,
+ slot);
+ };
+ conn("PrepareEncryptDiskResult", SLOT(onPreencryptResult(const QString &, const QString &, const QString &, int)));
+ conn("EncryptDiskResult", SLOT(onEncryptResult(const QString &, const QString &, int, const QString &)));
+ conn("EncryptProgress", SLOT(onEncryptProgress(const QString &, const QString &, double)));
+ conn("DecryptDiskResult", SLOT(onDecryptResult(const QString &, const QString &, const QString &, int)));
+ conn("DecryptProgress", SLOT(onDecryptProgress(const QString &, const QString &, double)));
+ conn("ChangePassphressResult", SLOT(onChgPassphraseResult(const QString &, const QString &, const QString &, int)));
+ conn("RequestEncryptParams", SLOT(onRequestEncryptParams(const QVariantMap &)));
+}
+
+void EventsHandler::hookEvents()
+{
+ dpfHookSequence->follow("dfmplugin_computer", "hook_Device_AcquireDevPwd",
+ this, &EventsHandler::onAcquireDevicePwd);
+}
+
+/**
+ * @brief EventsHandler::isTaskWorking, if any device is running encrypt, decrypt and change passphrase background
+ * @return
+ */
+bool EventsHandler::isTaskWorking()
+{
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ QDBusReply reply = iface.call("IsWorkerRunning");
+ return reply.isValid() && reply.value();
+}
+
+/**
+ * @brief EventsHandler::hasPendingTask, if task files existed in /boot/usec-crypt/
+ * @return
+ */
+bool EventsHandler::hasPendingTask()
+{
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ QDBusReply reply = iface.call("HasPendingTask");
+ return reply.isValid() && reply.value();
+}
+
+QString EventsHandler::unfinishedDecryptJob()
+{
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ QDBusReply reply = iface.call("UnfinishedDecryptJob");
+ return reply.value();
+}
+
+/**
+ * @brief EventsHandler::isUnderOperating, If the device is performing a task in the foreground
+ * @param device
+ * @return
+ */
+bool EventsHandler::isUnderOperating(const QString &device)
+{
+ return encryptDialogs.contains(device)
+ || decryptDialogs.contains(device)
+ || encryptInputs.contains(device);
+}
+
+int EventsHandler::deviceEncryptStatus(const QString &device)
+{
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ QDBusReply reply = iface.call("EncryptStatus", device);
+ if (reply.isValid())
+ return reply.value();
+ return -1;
+}
+
+void EventsHandler::resumeEncrypt(const QString &device)
+{
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ iface.asyncCall("ResumeEncryption", device);
+}
+
+void EventsHandler::onPreencryptResult(const QString &dev, const QString &devName, const QString &, int code)
+{
+ QApplication::restoreOverrideCursor();
+
+ if (code != kSuccess && code != -kRebootRequired) {
+ showPreEncryptError(dev, devName, code);
+ return;
+ }
+
+ // set dde-file-manager autostart without GUI to automatically raise the encrypt dialog.
+ autoStartDFM();
+
+ if (code == -kRebootRequired) {
+ qInfo() << "reboot is required..." << dev;
+ requestReboot();
+ }
+}
+
+void EventsHandler::onEncryptResult(const QString &dev, const QString &devName, int code, const QString &info)
+{
+ QApplication::restoreOverrideCursor();
+
+ // delay delete input dialogs. avoid when new request comes new dialog raises.
+ QTimer::singleShot(1000, this, [=] {
+ if (encryptInputs.contains(dev))
+ encryptInputs.take(dev)->deleteLater();
+ });
+
+ QString device = QString("%1(%2)").arg(devName).arg(dev.mid(5));
+ QString title, msg;
+ bool success = false;
+ switch (-code) {
+ case kUserCancelled:
+ ignoreParamRequest();
+ return;
+ case kSuccess:
+ case KErrorRequestExportRecKey:
+ title = tr("Encrypt done");
+ msg = tr("Device %1 has been encrypted").arg(device);
+ success = true;
+ break;
+ default:
+ title = tr("Encrypt failed");
+ msg = tr("Device %1 encrypt failed, please see log for more information.(%2)")
+ .arg(device)
+ .arg(code);
+ break;
+ }
+
+ auto dialog = encryptDialogs.take(dev);
+ if (!dialog)
+ dialog_utils::showDialog(title, msg, code != 0 ? dialog_utils::kError : dialog_utils::kInfo);
+ else {
+ auto pos = dialog->geometry().topLeft();
+ dialog->showResultPage(success, title, msg);
+ if (code == -KErrorRequestExportRecKey) {
+ dialog->setRecoveryKey(info, dev);
+ dialog->showExportPage();
+ }
+ dialog->move(pos);
+ }
+
+ // delete auto start file.
+ auto configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
+ auto autoStartFilePath = configPath + "/autostart/dfm-reencrypt.desktop";
+ int ret = ::remove(autoStartFilePath.toStdString().c_str());
+ qInfo() << "autostart file has been removed:" << ret;
+}
+
+void EventsHandler::onDecryptResult(const QString &dev, const QString &devName, const QString &, int code)
+{
+ QApplication::restoreOverrideCursor();
+ if (code == -kRebootRequired) {
+ requestReboot();
+ } else {
+ showDecryptError(dev, devName, code);
+
+ // delete auto start file.
+ auto configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
+ auto autoStartFilePath = configPath + "/autostart/dfm-reencrypt.desktop";
+ int ret = ::remove(autoStartFilePath.toStdString().c_str());
+ qInfo() << "autostart file has been removed:" << ret;
+ }
+}
+
+void EventsHandler::onChgPassphraseResult(const QString &dev, const QString &devName, const QString &, int code)
+{
+ QApplication::restoreOverrideCursor();
+ showChgPwdError(dev, devName, code);
+}
+
+void EventsHandler::onRequestEncryptParams(const QVariantMap &encConfig)
+{
+ qApp->restoreOverrideCursor();
+ QString devPath = encConfig.value("device-path").toString();
+ if (devPath.isEmpty()) {
+ qWarning() << "invalid encrypt config!" << encConfig;
+ return;
+ }
+
+ if (encryptInputs.value(devPath, nullptr))
+ return;
+
+ QString objPath = "/org/freedesktop/UDisks2/block_devices/" + devPath.mid(5);
+ auto blkDev = device_utils::createBlockDevice(objPath);
+ disk_encrypt::DeviceEncryptParam param;
+ param.devDesc = devPath;
+ param.initOnly = false;
+ param.clearDevUUID = encConfig.value("file-system-uuid").toString().remove("UUID=");
+ param.backingDevUUID = blkDev ? blkDev->getProperty(dfmmount::Property::kBlockIDUUID).toString() : "";
+ param.deviceDisplayName = encConfig.value("device-name").toString();
+ auto dlg = new EncryptParamsInputDialog(param, qApp->activeWindow());
+ encryptInputs.insert(devPath, dlg);
+
+ connect(dlg, &DDialog::finished, this, [=](auto ret) {
+ if (ret != QDialog::Accepted) {
+ ignoreParamRequest();
+ encryptInputs.take(devPath)->deleteLater(); // also will be deleted when encryption started.
+ } else {
+ DiskEncryptMenuScene::doReencryptDevice(dlg->getInputs());
+ }
+ });
+ dlg->show();
+}
+
+void EventsHandler::ignoreParamRequest()
+{
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ iface.asyncCall("IgnoreParamRequest");
+ qInfo() << "ignore param request...";
+}
+
+void EventsHandler::onEncryptProgress(const QString &dev, const QString &devName, double progress)
+{
+ if (!encryptDialogs.contains(dev)) {
+ QString device = QString("%1(%2)").arg(devName).arg(dev.mid(5));
+
+ QApplication::restoreOverrideCursor();
+ auto dlg = new EncryptProgressDialog(qApp->activeWindow());
+ dlg->setText(tr("%1 is under encrypting...").arg(device),
+ tr("The encrypting process may have system lag, please minimize the system operation"));
+ encryptDialogs.insert(dev, dlg);
+ }
+ auto dlg = encryptDialogs.value(dev);
+ dlg->updateProgress(progress);
+ dlg->show();
+
+ // when start encrypt, delete the inputs widget.
+ if (encryptInputs.contains(dev))
+ delete encryptInputs.take(dev);
+}
+
+void EventsHandler::onDecryptProgress(const QString &dev, const QString &devName, double progress)
+{
+ if (!decryptDialogs.contains(dev)) {
+ QString device = QString("%1(%2)").arg(devName).arg(dev.mid(5));
+
+ QApplication::restoreOverrideCursor();
+ auto dlg = new EncryptProgressDialog(qApp->activeWindow());
+ dlg->setText(tr("%1 is under decrypting...").arg(device),
+ tr("The decrypting process may have system lag, please minimize the system operation"));
+ decryptDialogs.insert(dev, dlg);
+ }
+
+ auto dlg = decryptDialogs.value(dev);
+ dlg->updateProgress(progress);
+ dlg->show();
+}
+
+bool EventsHandler::onAcquireDevicePwd(const QString &dev, QString *pwd, bool *cancelled)
+{
+ if (!pwd || !cancelled)
+ return false;
+
+ if (!canUnlock(dev)) {
+ *cancelled = true;
+ return true;
+ }
+
+ int type = device_utils::encKeyType(dev);
+
+ // test tpm
+ bool testTPM = (type == kTPMAndPIN || type == kTPMOnly);
+ if (testTPM && tpm_utils::checkTPM() != 0) {
+ qWarning() << "TPM service is not available.";
+ int ret = dialog_utils::showDialog(tr("Error"), tr("TPM status is abnormal, please use the recovery key to unlock it"),
+ dialog_utils::DialogType::kError);
+ // unlock by recovery key.
+ if (ret == 0)
+ *pwd = acquirePassphraseByRec(dev, *cancelled);
+
+ return true;
+ }
+
+ switch (type) {
+ case SecKeyType::kTPMAndPIN:
+ *pwd = acquirePassphraseByPIN(dev, *cancelled);
+ break;
+ case SecKeyType::kTPMOnly:
+ *pwd = acquirePassphraseByTPM(dev, *cancelled);
+ break;
+ case SecKeyType::kPasswordOnly:
+ *pwd = acquirePassphrase(dev, *cancelled);
+ break;
+ default:
+ return false;
+ }
+
+ if (pwd->isEmpty() && !*cancelled) {
+ QString title;
+ if (type == kTPMAndPIN)
+ title = tr("Wrong PIN");
+ else if (type == kPasswordOnly)
+ title = tr("Wrong passphrase");
+ else
+ title = tr("TPM error");
+
+ dialog_utils::showDialog(title, tr("Please use recovery key to unlock device."),
+ dialog_utils::kInfo);
+
+ *pwd = acquirePassphraseByRec(dev, *cancelled);
+ }
+
+ return true;
+}
+
+QString EventsHandler::acquirePassphrase(const QString &dev, bool &cancelled)
+{
+ UnlockPartitionDialog dlg(UnlockPartitionDialog::kPwd);
+ int ret = dlg.exec();
+ if (ret != 1) {
+ cancelled = true;
+ return "";
+ }
+ return dlg.getUnlockKey().second;
+}
+
+QString EventsHandler::acquirePassphraseByPIN(const QString &dev, bool &cancelled)
+{
+ UnlockPartitionDialog dlg(UnlockPartitionDialog::kPin);
+ int ret = dlg.exec();
+ if (ret != 1) {
+ cancelled = true;
+ return "";
+ }
+ auto keys = dlg.getUnlockKey();
+ if (keys.first == UnlockPartitionDialog::kPin)
+ return tpm_passphrase_utils::getPassphraseFromTPM_NonBlock(dev, keys.second);
+ else
+ return keys.second;
+}
+
+QString EventsHandler::acquirePassphraseByTPM(const QString &dev, bool &)
+{
+ return tpm_passphrase_utils::getPassphraseFromTPM_NonBlock(dev, "");
+}
+
+QString EventsHandler::acquirePassphraseByRec(const QString &dev, bool &cancelled)
+{
+ UnlockPartitionDialog dlg(UnlockPartitionDialog::kRec);
+ int ret = dlg.exec();
+ if (ret != 1) {
+ cancelled = true;
+ return "";
+ }
+ auto keys = dlg.getUnlockKey();
+ return keys.second;
+}
+
+void EventsHandler::showPreEncryptError(const QString &dev, const QString &devName, int code)
+{
+ QString title;
+ QString msg;
+ QString device = QString("%1(%2)").arg(devName).arg(dev.mid(5));
+
+ bool showError = false;
+ switch (-code) {
+ case (kSuccess):
+ title = tr("Preencrypt done");
+ msg = tr("Device %1 has been preencrypt, please reboot to finish encryption.")
+ .arg(device);
+ break;
+ case kUserCancelled:
+ return;
+ default:
+ title = tr("Preencrypt failed");
+ msg = tr("Device %1 preencrypt failed, please see log for more information.(%2)")
+ .arg(device)
+ .arg(code);
+ showError = true;
+ break;
+ }
+
+ dialog_utils::showDialog(title, msg,
+ showError ? dialog_utils::kError : dialog_utils::kInfo);
+}
+
+void EventsHandler::showDecryptError(const QString &dev, const QString &devName, int code)
+{
+ QString title;
+ QString msg;
+ QString device = QString("%1(%2)").arg(devName).arg(dev.mid(5));
+
+ bool showFailed = true;
+ switch (-code) {
+ case (kSuccess):
+ title = tr("Decrypt done");
+ msg = tr("Device %1 has been decrypted").arg(device);
+ showFailed = false;
+ break;
+ case kUserCancelled:
+ return;
+ case kErrorWrongPassphrase:
+ title = tr("Decrypt disk");
+ msg = tr("Wrong passpharse or PIN");
+ break;
+ case kErrorNotFullyEncrypted:
+ title = tr("Decrypt failed");
+ msg = tr("Device %1 is under encrypting, please decrypt after encryption finished.")
+ .arg(device);
+ break;
+ default:
+ title = tr("Decrypt failed");
+ msg = tr("Device %1 Decrypt failed, please see log for more information.(%2)")
+ .arg(device)
+ .arg(code);
+ break;
+ }
+
+ auto dialog = decryptDialogs.take(dev);
+ if (dialog) {
+ auto pos = dialog->geometry().topLeft();
+ dialog->showResultPage(code == 0, title, msg);
+ dialog->move(pos);
+ } else {
+ dialog_utils::showDialog(title, msg,
+ showFailed ? dialog_utils::kError : dialog_utils::kInfo);
+ }
+}
+
+void EventsHandler::showChgPwdError(const QString &dev, const QString &devName, int code)
+{
+ QString title;
+ QString msg;
+ QString device = QString("%1(%2)").arg(devName).arg(dev.mid(5));
+
+ int encType = device_utils::encKeyType(dev);
+ QString codeType;
+ switch (encType) {
+ case SecKeyType::kPasswordOnly:
+ codeType = tr("passphrase");
+ break;
+ default:
+ codeType = tr("PIN");
+ break;
+ }
+
+ bool showError = false;
+ switch (-code) {
+ case (kSuccess):
+ title = tr("Change %1 done").arg(codeType);
+ msg = tr("%1's %2 has been changed").arg(device).arg(codeType);
+ break;
+ case kUserCancelled:
+ return;
+ case kErrorChangePassphraseFailed:
+ title = tr("Change %1 failed").arg(codeType);
+ msg = tr("Wrong %1").arg(codeType);
+ showError = true;
+ break;
+ default:
+ title = tr("Change %1 failed").arg(codeType);
+ msg = tr("Device %1 change %2 failed, please see log for more information.(%3)")
+ .arg(device)
+ .arg(codeType)
+ .arg(code);
+ showError = true;
+ break;
+ }
+
+ dialog_utils::showDialog(title, msg,
+ showError ? dialog_utils::kError : dialog_utils::kInfo);
+}
+
+void EventsHandler::requestReboot()
+{
+ qWarning() << "reboot is confirmed...";
+ QDBusInterface sessMng("com.deepin.SessionManager",
+ "/com/deepin/SessionManager",
+ "com.deepin.SessionManager");
+ sessMng.asyncCall("RequestReboot");
+}
+
+bool EventsHandler::canUnlock(const QString &device)
+{
+ if (EventsHandler::instance()->isUnderOperating(device)) {
+ return false;
+ }
+
+ if (device == unfinishedDecryptJob()) {
+ dialog_utils::showDialog(tr("Error"),
+ tr("Device is not fully decrypted, please finish decryption before access."),
+ dialog_utils::DialogType::kInfo);
+ return false;
+ }
+
+ int states = EventsHandler::instance()->deviceEncryptStatus(device);
+ if ((states & kStatusOnline) && (states & kStatusEncrypt) && !(states & kStatusNoEncryptConfig)) {
+ dialog_utils::showDialog(tr("Unlocking device failed"),
+ tr("Please click the right disk menu \"Continue partition encryption\" to complete partition encryption."),
+ dialog_utils::DialogType::kError);
+ return false;
+ }
+
+ return true;
+}
+
+void EventsHandler::autoStartDFM()
+{
+ qInfo() << "autostart is going to added...";
+ QDBusInterface sessMng("com.deepin.SessionManager",
+ "/com/deepin/StartManager",
+ "com.deepin.StartManager");
+ sessMng.asyncCall("AddAutostart", QString(kReencryptDesktopFile));
+}
+
+EventsHandler::EventsHandler(QObject *parent)
+ : QObject { parent }
+{
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/events/eventshandler.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/events/eventshandler.h
new file mode 100644
index 0000000000..436bc0868e
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/events/eventshandler.h
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#ifndef EVENTSHANDLER_H
+#define EVENTSHANDLER_H
+
+#include
+#include
+
+namespace dfmplugin_diskenc {
+class EncryptProgressDialog;
+class EncryptParamsInputDialog;
+class EventsHandler : public QObject
+{
+ Q_OBJECT
+public:
+ static EventsHandler *instance();
+ void bindDaemonSignals();
+ void hookEvents();
+ bool isTaskWorking();
+ bool hasPendingTask();
+ QString unfinishedDecryptJob();
+ bool isUnderOperating(const QString &device);
+ int deviceEncryptStatus(const QString &device);
+ void resumeEncrypt(const QString &device);
+ bool onAcquireDevicePwd(const QString &dev, QString *pwd, bool *giveup);
+ void autoStartDFM();
+
+private Q_SLOTS:
+ void onPreencryptResult(const QString &, const QString &, const QString &, int);
+ void onEncryptResult(const QString &, const QString &, int, const QString &);
+ void onEncryptProgress(const QString &, const QString &, double);
+ void onDecryptResult(const QString &, const QString &, const QString &, int);
+ void onDecryptProgress(const QString &, const QString &, double);
+ void onChgPassphraseResult(const QString &, const QString &, const QString &, int);
+ void onRequestEncryptParams(const QVariantMap &encConfig);
+
+ void ignoreParamRequest();
+
+ QString acquirePassphrase(const QString &dev, bool &cancelled);
+ QString acquirePassphraseByPIN(const QString &dev, bool &cancelled);
+ QString acquirePassphraseByTPM(const QString &dev, bool &cancelled);
+ QString acquirePassphraseByRec(const QString &dev, bool &cancelled);
+
+ void showPreEncryptError(const QString &device, const QString &devName, int code);
+ void showDecryptError(const QString &device, const QString &devName, int code);
+ void showChgPwdError(const QString &device, const QString &devName, int code);
+
+ void requestReboot();
+ bool canUnlock(const QString &device);
+
+private:
+ explicit EventsHandler(QObject *parent = nullptr);
+
+ QMap encryptDialogs;
+ QMap decryptDialogs;
+ QMap encryptInputs;
+signals:
+};
+}
+#endif // EVENTSHANDLER_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/chgpassphrasedialog.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/chgpassphrasedialog.cpp
new file mode 100644
index 0000000000..1fe201963c
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/chgpassphrasedialog.cpp
@@ -0,0 +1,190 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#include "chgpassphrasedialog.h"
+#include "utils/encryptutils.h"
+
+#include
+#include
+#include
+
+using namespace dfmplugin_diskenc;
+
+ChgPassphraseDialog::ChgPassphraseDialog(const QString &device, QWidget *parent)
+ : Dtk::Widget::DDialog(parent),
+ device(device)
+{
+ int keyType = device_utils::encKeyType(device);
+ encType = tr("passphrase");
+ if (keyType == 1) // PIN
+ encType = tr("PIN");
+
+ initUI();
+
+ connect(this, &ChgPassphraseDialog::buttonClicked,
+ this, &ChgPassphraseDialog::onButtonClicked);
+ connect(recSwitch, &Dtk::Widget::DCommandLinkButton::clicked,
+ this, &ChgPassphraseDialog::onRecSwitchClicked);
+ connect(oldPass, &Dtk::Widget::DPasswordEdit::textChanged,
+ this, &ChgPassphraseDialog::onOldKeyChanged);
+ if (dialog_utils::isWayland())
+ setWindowFlag(Qt::WindowStaysOnTopHint);
+}
+
+QPair ChgPassphraseDialog::getPassphrase()
+{
+ QString oldKey = oldPass->text();
+ if (usingRecKey)
+ oldKey.remove("-");
+ return { oldKey, newPass1->text() };
+}
+
+bool ChgPassphraseDialog::validateByRecKey()
+{
+ return usingRecKey;
+}
+
+void ChgPassphraseDialog::initUI()
+{
+ setIcon(QIcon::fromTheme("drive-harddisk-root"));
+
+ int keyType = device_utils::encKeyType(device);
+ QString keyTypeStr = tr("passphrase");
+ if (keyType == 1) // PIN
+ keyTypeStr = tr("PIN");
+
+ setTitle(tr("Modify %1").arg(keyTypeStr));
+ QFrame *content = new QFrame(this);
+ QVBoxLayout *contentLay = new QVBoxLayout(content);
+ QFormLayout *lay = new QFormLayout();
+ contentLay->addLayout(lay);
+
+ oldKeyHint = new QLabel(this);
+ oldPass = new Dtk::Widget::DPasswordEdit(this);
+ newPass1 = new Dtk::Widget::DPasswordEdit(this);
+ newPass2 = new Dtk::Widget::DPasswordEdit(this);
+
+ newPass2->setPlaceholderText(tr("Please enter %1 again").arg(keyTypeStr));
+
+ lay->addRow(oldKeyHint, oldPass);
+ lay->addRow(tr("New %1").arg(encType), newPass1);
+ lay->addRow(tr("Repeat %1").arg(encType), newPass2);
+
+ recSwitch = new Dtk::Widget::DCommandLinkButton("", this);
+ contentLay->addWidget(recSwitch, 0, Qt::AlignRight);
+
+ addContent(content);
+ addButton(tr("Cancel"));
+ addButton(tr("Confirm"));
+
+ setOnButtonClickedClose(false);
+
+ usingRecKey = true;
+ onRecSwitchClicked();
+
+ setMinimumWidth(500);
+
+ oldPass->setFocus();
+}
+
+bool ChgPassphraseDialog::validatePasswd()
+{
+ int keyType = device_utils::encKeyType(device);
+ QString keyTypeStr = tr("passphrase");
+ if (keyType == 1) // PIN
+ keyTypeStr = tr("PIN");
+
+ auto nonEmpty = [=](Dtk::Widget::DPasswordEdit *editor) {
+ QString pwd = editor->text().trimmed();
+ if (!pwd.isEmpty()) return true;
+
+ editor->showAlertMessage(tr("%1 cannot be empty").arg(keyTypeStr));
+ return false;
+ };
+
+ QString oldKey = oldPass->text().trimmed();
+ if (oldKey.isEmpty()) {
+ QString msg = tr("%1 cannot be empty");
+ if (usingRecKey)
+ msg = msg.arg(tr("Recovery key"));
+ else
+ msg = msg.arg(encType);
+ oldPass->showAlertMessage(msg);
+ return false;
+ } else if (usingRecKey && oldKey.remove("-").length() != 24) {
+ oldPass->showAlertMessage(tr("Recovery key is not valid!"));
+ return false;
+ }
+
+ if (!(nonEmpty(newPass1)
+ && nonEmpty(newPass2)))
+ return false;
+
+ QList regx {
+ QRegularExpression { R"([A-Z])" },
+ QRegularExpression { R"([a-z])" },
+ QRegularExpression { R"([0-9])" },
+ QRegularExpression { R"([^A-Za-z0-9])" }
+ };
+
+ QString pwd1 = newPass1->text().trimmed();
+ QString pwd2 = newPass2->text().trimmed();
+
+ int factor = 0;
+ std::for_each(regx.cbegin(), regx.cend(), [&factor, pwd1](const QRegularExpression ®) {
+ if (pwd1.contains(reg))
+ factor += 1;
+ });
+
+ if (factor < 3 || pwd1.length() < 8) {
+ newPass1->showAlertMessage(tr("At least 8 bits, contains 3 types of A-Z, a-z, 0-9 and symbols"));
+ return false;
+ }
+
+ if (pwd1 != pwd2) {
+ newPass2->showAlertMessage(tr("%1 inconsistency").arg(keyTypeStr));
+ return false;
+ }
+
+ return true;
+}
+
+void ChgPassphraseDialog::onButtonClicked(int idx)
+{
+ if (idx == 1) {
+ if (!validatePasswd())
+ return;
+ accept();
+ } else {
+ reject();
+ }
+}
+
+void ChgPassphraseDialog::onRecSwitchClicked()
+{
+ usingRecKey = !usingRecKey;
+ oldPass->clear();
+ if (usingRecKey) {
+ oldKeyHint->setText(tr("Recovery key"));
+ oldPass->setEchoMode(QLineEdit::Normal);
+ oldPass->setEchoButtonIsVisible(false);
+ recSwitch->setText(tr("Validate with %1").arg(encType));
+ oldPass->setPlaceholderText(tr("Please input recovery key"));
+ } else {
+ oldKeyHint->setText(tr("Old %1").arg(encType));
+ oldPass->setEchoMode(QLineEdit::Password);
+ oldPass->setEchoButtonIsVisible(true);
+ recSwitch->setText(tr("Validate with recovery key"));
+ oldPass->setPlaceholderText(tr("At least 8 bits, contains 3 types of A-Z, a-z, 0-9 and symbols"));
+ }
+ newPass1->setPlaceholderText(tr("At least 8 bits, contains 3 types of A-Z, a-z, 0-9 and symbols"));
+ oldPass->setFocus();
+}
+
+void ChgPassphraseDialog::onOldKeyChanged(const QString &inputs)
+{
+ if (usingRecKey) {
+ QSignalBlocker blocker(sender());
+ oldPass->setText(recovery_key_utils::formatRecoveryKey(inputs));
+ }
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/chgpassphrasedialog.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/chgpassphrasedialog.h
new file mode 100644
index 0000000000..822316191d
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/chgpassphrasedialog.h
@@ -0,0 +1,43 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#ifndef CHGPASSPHRASEDIALOG_H
+#define CHGPASSPHRASEDIALOG_H
+
+#include
+#include
+#include
+
+namespace dfmplugin_diskenc {
+
+class ChgPassphraseDialog : public Dtk::Widget::DDialog
+{
+ Q_OBJECT
+public:
+ explicit ChgPassphraseDialog(const QString &device, QWidget *parent = nullptr);
+ QPair getPassphrase();
+ bool validateByRecKey();
+
+protected:
+ void initUI();
+ bool validatePasswd();
+
+protected Q_SLOTS:
+ void onButtonClicked(int idx);
+ void onRecSwitchClicked();
+ void onOldKeyChanged(const QString &inputs);
+
+private:
+ QString device;
+ QString encType;
+ bool usingRecKey { false };
+
+ QLabel *oldKeyHint { nullptr };
+ Dtk::Widget::DPasswordEdit *oldPass { nullptr };
+ Dtk::Widget::DPasswordEdit *newPass1 { nullptr };
+ Dtk::Widget::DPasswordEdit *newPass2 { nullptr };
+ Dtk::Widget::DCommandLinkButton *recSwitch { nullptr };
+};
+
+}
+#endif // CHGPASSPHRASEDIALOG_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/decryptparamsinputdialog.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/decryptparamsinputdialog.cpp
new file mode 100644
index 0000000000..bde2bc9acb
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/decryptparamsinputdialog.cpp
@@ -0,0 +1,115 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#include "decryptparamsinputdialog.h"
+#include "utils/encryptutils.h"
+
+#include
+
+using namespace dfmplugin_diskenc;
+DecryptParamsInputDialog::DecryptParamsInputDialog(const QString &device, QWidget *parent)
+ : Dtk::Widget::DDialog(parent), devDesc(device)
+{
+ initUI();
+ connect(recSwitch, &Dtk::Widget::DCommandLinkButton::clicked,
+ this, &DecryptParamsInputDialog::onRecSwitchClicked);
+ connect(editor, &Dtk::Widget::DPasswordEdit::textChanged,
+ this, &DecryptParamsInputDialog::onKeyChanged);
+ connect(this, &DecryptParamsInputDialog::buttonClicked,
+ this, &DecryptParamsInputDialog::onButtonClicked);
+ updateUserHints();
+ if (dialog_utils::isWayland())
+ setWindowFlag(Qt::WindowStaysOnTopHint);
+}
+
+QString DecryptParamsInputDialog::getKey()
+{
+ QString key = editor->text();
+ if (usingRecKey())
+ key.remove("-");
+ return key;
+}
+
+void DecryptParamsInputDialog::setInputPIN(bool pin)
+{
+ requestPIN = pin;
+ updateUserHints();
+}
+
+bool DecryptParamsInputDialog::usingRecKey()
+{
+ return useRecKey;
+}
+
+void DecryptParamsInputDialog::onRecSwitchClicked()
+{
+ useRecKey = !useRecKey;
+ editor->clear();
+ if (useRecKey) {
+ editor->setEchoMode(QLineEdit::Normal);
+ editor->setEchoButtonIsVisible(false);
+ editor->setPlaceholderText(tr("Please input recovery key to decrypt device"));
+ recSwitch->setText(tr("Validate with %1").arg(requestPIN ? tr("PIN") : tr("passphrase")));
+ } else {
+ editor->setEchoMode(QLineEdit::Password);
+ editor->setEchoButtonIsVisible(true);
+ editor->setPlaceholderText(tr("Please input %1 to decrypt device").arg(requestPIN ? tr("PIN") : tr("passphrase")));
+ recSwitch->setText(tr("Validate with recovery key"));
+ }
+ editor->setFocus();
+}
+
+void DecryptParamsInputDialog::onKeyChanged(const QString &key)
+{
+ if (!usingRecKey())
+ return;
+ QSignalBlocker blocker(sender());
+ auto formatted = recovery_key_utils::formatRecoveryKey(key);
+ editor->setText(formatted);
+}
+
+void DecryptParamsInputDialog::onButtonClicked(int idx)
+{
+ if (idx != 0) {
+ reject();
+ return;
+ }
+
+ if (getKey().isEmpty()) {
+ QString keyType = requestPIN ? tr("PIN") : tr("Passphrase");
+ if (usingRecKey())
+ keyType = tr("Recovery key");
+ editor->showAlertMessage(tr("%1 cannot be empty!").arg(keyType));
+ return;
+ }
+
+ else if (usingRecKey() && getKey().length() != 24) {
+ editor->showAlertMessage(tr("Recovery key is not valid!"));
+ return;
+ }
+
+ accept();
+}
+
+void DecryptParamsInputDialog::updateUserHints()
+{
+ useRecKey = true;
+ onRecSwitchClicked();
+}
+
+void DecryptParamsInputDialog::initUI()
+{
+ setIcon(QIcon::fromTheme("drive-harddisk-root"));
+ setTitle(tr("Decrypt device"));
+ QFrame *content = new QFrame(this);
+ QVBoxLayout *lay = new QVBoxLayout(content);
+ editor = new Dtk::Widget::DPasswordEdit(this);
+ lay->addWidget(editor);
+ recSwitch = new Dtk::Widget::DCommandLinkButton("", this);
+ lay->addWidget(recSwitch, 0, Qt::AlignRight);
+ addContent(content);
+ addButton(tr("Confirm"));
+ setOnButtonClickedClose(false);
+
+ editor->setFocus();
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/decryptparamsinputdialog.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/decryptparamsinputdialog.h
new file mode 100644
index 0000000000..506ed0067c
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/decryptparamsinputdialog.h
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#ifndef DECRYPTPARAMSINPUTDIALOG_H
+#define DECRYPTPARAMSINPUTDIALOG_H
+
+#include
+#include
+#include
+
+namespace dfmplugin_diskenc {
+
+class DecryptParamsInputDialog : public Dtk::Widget::DDialog
+{
+ Q_OBJECT
+public:
+ explicit DecryptParamsInputDialog(const QString &device, QWidget *parent = nullptr);
+ QString getKey();
+ void setInputPIN(bool);
+ bool usingRecKey();
+
+protected:
+ void onRecSwitchClicked();
+ void onKeyChanged(const QString &key);
+ void onButtonClicked(int idx);
+ void updateUserHints();
+
+protected:
+ void initUI();
+
+private:
+ QString devDesc;
+ QString passphrase;
+ bool useRecKey { false };
+ bool requestPIN { false };
+
+ Dtk::Widget::DPasswordEdit *editor { nullptr };
+ Dtk::Widget::DCommandLinkButton *recSwitch { nullptr };
+};
+
+}
+#endif // DECRYPTPARAMSINPUTDIALOG_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptparamsinputdialog.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptparamsinputdialog.cpp
new file mode 100644
index 0000000000..657839e394
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptparamsinputdialog.cpp
@@ -0,0 +1,430 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "encryptparamsinputdialog.h"
+#include "utils/encryptutils.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+using namespace dfmplugin_diskenc;
+using namespace disk_encrypt;
+DWIDGET_USE_NAMESPACE
+
+enum StepPage {
+ kPasswordInputPage,
+ kExportKeyPage,
+};
+
+EncryptParamsInputDialog::EncryptParamsInputDialog(const disk_encrypt::DeviceEncryptParam ¶ms,
+ QWidget *parent)
+ : DTK_WIDGET_NAMESPACE::DDialog(parent),
+ params(params)
+{
+ exportRecKeyEnabled = config_utils::exportKeyEnabled();
+ initUi();
+ initConn();
+ if (dialog_utils::isWayland())
+ setWindowFlag(Qt::WindowStaysOnTopHint);
+}
+
+DeviceEncryptParam EncryptParamsInputDialog::getInputs()
+{
+ QString password;
+ if (kTPMAndPIN == encType->currentIndex() || kTPMOnly == encType->currentIndex()) {
+ password = tpmPassword;
+ tpmPassword.clear();
+ } else if (kPasswordOnly == encType->currentIndex()) {
+ password = encKeyEdit1->text();
+ }
+
+ params.type = static_cast(encType->currentIndex());
+ params.key = password;
+ params.exportPath = keyExportInput->text();
+ return params;
+}
+
+void EncryptParamsInputDialog::initUi()
+{
+ clearContents();
+ setOnButtonClickedClose(false);
+ setFixedSize(472, 304);
+ setIcon(QIcon::fromTheme("drive-harddisk"));
+
+ QWidget *center = new QWidget(this);
+ center->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ addContent(center);
+
+ pagesLay = new QStackedLayout(this);
+ center->setLayout(pagesLay);
+
+ pagesLay->addWidget(createPasswordPage());
+ pagesLay->addWidget(createExportPage());
+
+ onPageChanged(kPasswordInputPage);
+
+ // for ui debugging
+ // setStyleSheet("border: 1px solid red;");
+ // center->setObjectName("center");
+ // center->setStyleSheet("QWidget#center{border: 1px solid red;}");
+}
+
+void EncryptParamsInputDialog::initConn()
+{
+ connect(pagesLay, &QStackedLayout::currentChanged,
+ this, &EncryptParamsInputDialog::onPageChanged);
+ connect(this, &EncryptParamsInputDialog::buttonClicked,
+ this, &EncryptParamsInputDialog::onButtonClicked);
+ connect(encType, static_cast(&DComboBox::currentIndexChanged),
+ this, &EncryptParamsInputDialog::onEncTypeChanged);
+ connect(keyExportInput, &DFileChooserEdit::textChanged,
+ this, [this](const QString &path) { onExpPathChanged(path, false); });
+}
+
+QWidget *EncryptParamsInputDialog::createPasswordPage()
+{
+ QWidget *wid = new QWidget(this);
+ QFormLayout *lay = new QFormLayout();
+ lay->setContentsMargins(0, 10, 0, 0);
+ wid->setLayout(lay);
+
+ encType = new DComboBox(this);
+ encType->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
+ lay->addRow(tr("Unlock type"), encType);
+
+ unlockTypeHint = new QLabel(this); /*tr("User access to the partition is automatically "
+ "unlocked without passphrase checking.")*/
+ unlockTypeHint->setWordWrap(true);
+ lay->addRow("", unlockTypeHint);
+ auto font = unlockTypeHint->font();
+ font.setPixelSize(12);
+ unlockTypeHint->setFont(font);
+ unlockTypeHint->setFixedWidth(360);
+
+ keyHint1 = new QLabel(this);
+ encKeyEdit1 = new DPasswordEdit(this);
+ keyHint1->setMinimumWidth(66);
+ lay->addRow(keyHint1, encKeyEdit1);
+
+ keyHint2 = new QLabel(this);
+ encKeyEdit2 = new DPasswordEdit(this);
+ lay->addRow(keyHint2, encKeyEdit2);
+
+ encType->addItems({ tr("Unlocked by passphrase"),
+ tr("Use TPM+PIN to unlock on this computer (recommended)"),
+ tr("Automatic unlocking on this computer by TPM") });
+
+ if (tpm_utils::checkTPM() != 0) {
+ // encType->setItemData(kTPMAndPIN, QVariant(0), Qt::UserRole - 1);
+ // encType->setItemData(kTPMOnly, QVariant(0), Qt::UserRole - 1);
+ encType->removeItem(1);
+ encType->removeItem(1);
+
+ encType->setCurrentIndex(kPasswordOnly);
+ onEncTypeChanged(kPasswordOnly);
+ } else {
+ encType->setCurrentIndex(kTPMAndPIN);
+ onEncTypeChanged(kTPMAndPIN);
+ }
+
+ return wid;
+}
+
+QWidget *EncryptParamsInputDialog::createExportPage()
+{
+ QVBoxLayout *lay = new QVBoxLayout();
+ QWidget *wid = new QWidget(this);
+ wid->setLayout(lay);
+ lay->setMargin(0);
+
+ QLabel *hint = new QLabel(tr("In special cases such as forgetting the password or the encryption hardware is damaged, "
+ "you can decrypt the encrypted partition with the recovery key, please export it to "
+ "a non-encrypted partition and keep it in a safe place!"),
+ this);
+ hint->setWordWrap(true);
+ hint->adjustSize();
+ lay->addWidget(hint);
+ hint->setAlignment(Qt::AlignCenter);
+
+ keyExportInput = new DFileChooserEdit(this);
+ keyExportInput->setFileMode(QFileDialog::DirectoryOnly);
+ if (keyExportInput->fileDialog() && dialog_utils::isWayland())
+ keyExportInput->fileDialog()->setWindowFlag(Qt::WindowStaysOnTopHint);
+ lay->addWidget(keyExportInput);
+
+ keyExportInput->setPlaceholderText(tr("Please select a non-encrypted partition as the key file export path."));
+
+ return wid;
+}
+
+bool EncryptParamsInputDialog::validatePassword()
+{
+ if (pagesLay->currentIndex() != kPasswordInputPage)
+ return false;
+
+ if (encType->currentIndex() == kTPMOnly)
+ return true;
+
+ QString pwd1 = encKeyEdit1->text().trimmed();
+ QString pwd2 = encKeyEdit2->text().trimmed();
+
+ QString keyType;
+ if (encType->currentIndex() == kTPMAndPIN)
+ keyType = "PIN";
+ else if (encType->currentIndex() == kPasswordOnly)
+ keyType = tr("Passphrase");
+
+ QString hint = tr("%1 cannot be empty").arg(keyType);
+
+ if (pwd1.isEmpty()) {
+ encKeyEdit1->showAlertMessage(hint);
+ return false;
+ }
+
+ if (pwd2.isEmpty()) {
+ encKeyEdit2->showAlertMessage(hint);
+ return false;
+ }
+
+ QList regx {
+ QRegularExpression { R"([A-Z])" },
+ QRegularExpression { R"([a-z])" },
+ QRegularExpression { R"([0-9])" },
+ QRegularExpression { R"([^A-Za-z0-9])" }
+ };
+
+ int factor = 0;
+ std::for_each(regx.cbegin(), regx.cend(), [&factor, pwd1](const QRegularExpression ®) {
+ if (pwd1.contains(reg))
+ factor += 1;
+ });
+
+ if (factor < 3 || pwd1.length() < 8) {
+ encKeyEdit1->showAlertMessage(tr("At least 8 bits, contains 3 types of A-Z, a-z, 0-9 and symbols"));
+ return false;
+ }
+
+ if (pwd1 != pwd2) {
+ encKeyEdit2->showAlertMessage(tr("%1 inconsistency").arg(keyType));
+ return false;
+ }
+
+ return true;
+}
+
+bool EncryptParamsInputDialog::validateExportPath(const QString &path, QString *msg)
+{
+ auto setMsg = [&](const QString &info) { if (msg) *msg = info; };
+ if (path.isEmpty()) {
+ setMsg(tr("Recovery key export path cannot be empty!"));
+ return false;
+ }
+
+ if (!QDir(path).exists()) {
+ setMsg(tr("Recovery key export path is not exists!"));
+ return false;
+ }
+
+ QStorageInfo storage(path);
+ QString dev = storage.device();
+ if (dev == params.devDesc) {
+ setMsg(tr("Please export to an external device such as a non-encrypted partition or USB flash drive."));
+ return false;
+ }
+
+ if (storage.isReadOnly()) {
+ setMsg(tr("This partition is read-only, please export to a writable partition"));
+ return false;
+ }
+
+ using namespace dfmmount;
+ auto monitor = DDeviceManager::instance()->getRegisteredMonitor(DeviceType::kBlockDevice).objectCast();
+ Q_ASSERT(monitor);
+ auto devObjPaths = monitor->resolveDeviceNode(dev, {});
+ if (!devObjPaths.isEmpty()) {
+ auto objPath = devObjPaths.constFirst();
+ auto devPtr = monitor->createDeviceById(objPath);
+ if (devPtr && devPtr->getProperty(Property::kBlockCryptoBackingDevice).toString() != "/") {
+ setMsg(tr("The partition is encrypted, please export to a non-encrypted "
+ "partition or external device such as a USB flash drive."));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void EncryptParamsInputDialog::setPasswordInputVisible(bool visible)
+{
+ keyHint1->setVisible(visible);
+ keyHint2->setVisible(visible);
+ encKeyEdit1->setVisible(visible);
+ encKeyEdit2->setVisible(visible);
+}
+
+void EncryptParamsInputDialog::onButtonClicked(int idx)
+{
+ qDebug() << "button clicked:" << idx << "page: " << pagesLay->currentIndex();
+
+ int currPage = pagesLay->currentIndex();
+ if (currPage == kPasswordInputPage) {
+ if (!validatePassword() && !params.initOnly)
+ return;
+
+ if (exportRecKeyEnabled) {
+ pagesLay->setCurrentIndex(kExportKeyPage);
+ onExpPathChanged(keyExportInput->text(), true);
+ } else {
+ confirmEncrypt();
+ }
+ } else if (currPage == kExportKeyPage) {
+ if (idx == 0)
+ pagesLay->setCurrentIndex(kPasswordInputPage);
+ else if (idx == 1)
+ confirmEncrypt();
+ }
+}
+
+void EncryptParamsInputDialog::onPageChanged(int page)
+{
+ if (page > kExportKeyPage && page < kPasswordInputPage) {
+ qWarning() << "invalid page index!" << page;
+ return;
+ }
+
+ pagesLay->setCurrentIndex(page);
+ clearButtons();
+ if (page == kPasswordInputPage) {
+ QString devName = QString("%1(%2)").arg(params.deviceDisplayName).arg(params.devDesc.mid(5));
+ setTitle(tr("Please continue to encrypt partition %1").arg(devName));
+ exportRecKeyEnabled ? addButton(tr("Next")) : addButton(tr("Confirm encrypt"));
+ encKeyEdit1->setFocus();
+ } else if (page == kExportKeyPage) {
+ setTitle(tr("Export Recovery Key"));
+ addButton(tr("Previous"));
+ addButton(tr("Confirm encrypt"), true, ButtonType::ButtonRecommend);
+ keyExportInput->setFocus();
+ }
+}
+
+void EncryptParamsInputDialog::onEncTypeChanged(int type)
+{
+ QString filed1 = tr("Set %1");
+ QString filed2 = tr("Repeat %1");
+ QString placeholder1 = tr("At least 8 bits, contains 3 types of A-Z, a-z, 0-9 and symbols");
+ QString placeholder2 = tr("Please enter the %1 again");
+
+ if (type == kPasswordOnly) {
+ setPasswordInputVisible(true);
+ keyHint1->setText(filed1.arg(tr("passphrase")));
+ keyHint2->setText(filed2.arg(tr("passphrase")));
+ encKeyEdit1->setPlaceholderText(placeholder1);
+ encKeyEdit2->setPlaceholderText(placeholder2.arg(tr("Passphrase")));
+ unlockTypeHint->setText(tr("Access to the partition will be unlocked using a passphrase."));
+ } else if (type == kTPMAndPIN) {
+ setPasswordInputVisible(true);
+ keyHint1->setText(filed1.arg(tr("PIN")));
+ keyHint2->setText(filed2.arg(tr("PIN")));
+ encKeyEdit1->setPlaceholderText(placeholder1);
+ encKeyEdit2->setPlaceholderText(placeholder2.arg(tr("PIN")));
+ unlockTypeHint->setText(tr("Access to the partition will be unlocked using the TPM security chip and PIN."));
+ } else if (type == kTPMOnly) {
+ setPasswordInputVisible(false);
+ unlockTypeHint->setText(tr("Access to the partition will be automatically unlocked using the TPM security chip, "
+ "no passphrase checking is required."));
+ } else {
+ qWarning() << "wrong encrypt type!" << type;
+ }
+
+ if (params.initOnly)
+ setPasswordInputVisible(false);
+}
+
+void EncryptParamsInputDialog::onExpPathChanged(const QString &path, bool silent)
+{
+ auto btnNext = getButton(1);
+ if (!btnNext)
+ return;
+ QString msg;
+ btnNext->setEnabled(validateExportPath(path, &msg));
+ if (!msg.isEmpty() && !silent)
+ keyExportInput->showAlertMessage(msg);
+}
+
+bool EncryptParamsInputDialog::encryptByTpm(const QString &deviceName)
+{
+ auto btns = this->getButtons();
+ for (auto btn : btns)
+ btn->setEnabled(false);
+ dfmbase::FinallyUtil finalClear([=] {
+ for (auto btn : btns)
+ btn->setEnabled(true);
+ });
+
+ QString sessionHashAlgo, sessionKeyAlgo, primaryHashAlgo, primaryKeyAlgo, minorHashAlgo, minorKeyAlgo;
+ bool checkAlgo = tpm_passphrase_utils::getAlgorithm(&sessionHashAlgo,
+ &sessionKeyAlgo,
+ &primaryHashAlgo,
+ &primaryKeyAlgo,
+ &minorHashAlgo,
+ &minorKeyAlgo);
+ if (!checkAlgo) {
+ qCritical() << "TPM algo choice failed!";
+ return false;
+ }
+
+ DSpinner spinner(this);
+ spinner.setFixedSize(50, 50);
+ spinner.move((width() - spinner.width()) / 2, (height() - spinner.height()) / 2);
+ spinner.start();
+ spinner.show();
+
+ QString pin = (encType->currentIndex() == SecKeyType::kTPMAndPIN)
+ ? encKeyEdit1->text()
+ : "";
+ int exitCode = tpm_passphrase_utils::genPassphraseFromTPM_NonBlock(deviceName, pin, &tpmPassword);
+ if (exitCode != 0) {
+ qCritical() << "TPM encrypt failed!";
+ // dialog_utils::showTPMError(tr("Encrypt failed"),
+ // static_cast(exitCode));
+ return false;
+ }
+ return true;
+}
+
+void EncryptParamsInputDialog::confirmEncrypt()
+{
+ if (encType->currentIndex() == kPasswordOnly) {
+ accept();
+ return;
+ }
+ if (!params.initOnly && !encryptByTpm(params.devDesc)) {
+ qWarning() << "encrypt by TPM failed!";
+ if (tpm_utils::ownerAuthStatus() == 1) {
+ QString msg = tr("TPM is locked and cannot be used for partition encryption. "
+ "Please cancel the TPM password or choose another unlocking method.");
+ dialog_utils::showDialog(tr("TPM error"), msg, dialog_utils::DialogType::kError);
+ return;
+ }
+ dialog_utils::showDialog(tr("TPM error"), tr("TPM status error!"), dialog_utils::DialogType::kError);
+ return;
+ }
+ accept();
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptparamsinputdialog.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptparamsinputdialog.h
new file mode 100644
index 0000000000..b96d2fccec
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptparamsinputdialog.h
@@ -0,0 +1,71 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef ENCRYPTPARAMSINPUTDIALOG_H
+#define ENCRYPTPARAMSINPUTDIALOG_H
+
+#include "dfmplugin_disk_encrypt_global.h"
+
+#include
+#include
+
+DWIDGET_BEGIN_NAMESPACE
+class DPasswordEdit;
+class DFileChooserEdit;
+class DComboBox;
+class DLineEdit;
+DWIDGET_END_NAMESPACE
+
+class QLabel;
+class QStackedLayout;
+class QLayout;
+
+namespace dfmplugin_diskenc {
+
+class EncryptParamsInputDialog : public DTK_WIDGET_NAMESPACE::DDialog
+{
+ Q_OBJECT
+public:
+ explicit EncryptParamsInputDialog(const disk_encrypt::DeviceEncryptParam ¶ms, QWidget *parent = nullptr);
+ disk_encrypt::DeviceEncryptParam getInputs();
+
+protected:
+ void initUi();
+ void initConn();
+ QWidget *createPasswordPage();
+ QWidget *createExportPage();
+ bool validatePassword();
+ bool validateExportPath(const QString &path, QString *msg);
+ void setPasswordInputVisible(bool visible);
+
+protected Q_SLOTS:
+ void onButtonClicked(int idx);
+ void onPageChanged(int page);
+ void onEncTypeChanged(int type);
+ void onExpPathChanged(const QString &path, bool silent);
+
+private:
+ bool encryptByTpm(const QString &deviceName);
+ void confirmEncrypt();
+
+private:
+ DTK_WIDGET_NAMESPACE::DComboBox *encType { nullptr };
+ DTK_WIDGET_NAMESPACE::DPasswordEdit *encKeyEdit1 { nullptr };
+ DTK_WIDGET_NAMESPACE::DPasswordEdit *encKeyEdit2 { nullptr };
+ DTK_WIDGET_NAMESPACE::DFileChooserEdit *keyExportInput { nullptr };
+
+ QLabel *keyHint1 { nullptr };
+ QLabel *keyHint2 { nullptr };
+ QLabel *unlockTypeHint { nullptr };
+ QStackedLayout *pagesLay { nullptr };
+
+private:
+ bool expPathValid { false };
+ bool exportRecKeyEnabled { false };
+ QString tpmPassword;
+ disk_encrypt::DeviceEncryptParam params;
+};
+
+}
+#endif // ENCRYPTPARAMSINPUTDIALOG_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptprogressdialog.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptprogressdialog.cpp
new file mode 100644
index 0000000000..287a15f6ee
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptprogressdialog.cpp
@@ -0,0 +1,190 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "encryptprogressdialog.h"
+#include "utils/encryptutils.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+using namespace dfmplugin_diskenc;
+
+EncryptProgressDialog::EncryptProgressDialog(QWidget *parent)
+ : DDialog(parent)
+{
+ initUI();
+}
+
+void EncryptProgressDialog::setText(const QString &title, const QString &message)
+{
+ setTitle(title);
+ this->message->setText(message);
+}
+
+void EncryptProgressDialog::updateProgress(double progress)
+{
+ mainLay->setCurrentIndex(0);
+ int val = progress * 100 - 1; // do not show 100%, wait at 99% and then jump to result page.
+ if (val < 0) val = 0;
+ this->progress->setValue(val);
+ clearButtons();
+ setCloseButtonVisible(false);
+}
+
+void EncryptProgressDialog::showResultPage(bool success, const QString &title, const QString &message)
+{
+ this->progress->setValue(100);
+ mainLay->setCurrentIndex(1);
+
+ setTitle(title);
+ resultMsg->setText(message);
+ QIcon icon = success ? QIcon::fromTheme("dialog-ok") : QIcon::fromTheme("dialog-error");
+ iconLabel->setPixmap(icon.pixmap(64, 64));
+
+ addButton(tr("Confirm"));
+ setCloseButtonVisible(true);
+ setAttribute(Qt::WA_DeleteOnClose);
+ setOnButtonClickedClose(true);
+}
+
+void EncryptProgressDialog::showExportPage()
+{
+ clearButtons();
+ addButton(tr("Re-export the recovery key"));
+ setOnButtonClickedClose(false);
+ setCloseButtonVisible(false);
+
+ warningLabel->setText(tr("*Recovery key saving failed, please re-save the recovery "
+ "key to a non-encrypted partition and keep it in a safe place!"));
+ warningLabel->setVisible(true);
+
+ connect(this, &EncryptProgressDialog::buttonClicked,
+ this, &EncryptProgressDialog::onCicked);
+}
+
+void EncryptProgressDialog::onCicked(int idx, const QString &btnTxt)
+{
+ if (btnTxt != tr("Re-export the recovery key"))
+ return;
+ QUrl url = DFileDialog::getExistingDirectoryUrl(this);
+ QString msg;
+ if (!validateExportPath(url.toLocalFile(), &msg)) {
+ dialog_utils::showDialog(tr("Error"), msg, dialog_utils::DialogType::kError);
+ } else {
+ saveRecKey(url.toLocalFile());
+ }
+}
+
+void EncryptProgressDialog::initUI()
+{
+ clearContents();
+ setIcon(QIcon::fromTheme("drive-harddisk-root"));
+ setFixedWidth(400);
+
+ QFrame *frame = new QFrame(this);
+ mainLay = new QStackedLayout(frame);
+ mainLay->setContentsMargins(0, 0, 0, 0);
+ mainLay->setSpacing(0);
+ addContent(frame);
+
+ QFrame *progressPage = new QFrame(this);
+ QVBoxLayout *progressLay = new QVBoxLayout(progressPage);
+ progressLay->setSpacing(30);
+ progressLay->setContentsMargins(0, 30, 0, 20);
+
+ progress = new DWaterProgress(this);
+ progress->setFixedSize(64, 64);
+ progress->setValue(1);
+ progressLay->addWidget(progress, 0, Qt::AlignCenter);
+ progress->start();
+
+ message = new QLabel(this);
+ progressLay->addWidget(message, 0, Qt::AlignCenter);
+
+ QFrame *resultPage = new QFrame(this);
+ QVBoxLayout *resultLay = new QVBoxLayout(resultPage);
+ resultLay->setSpacing(20);
+ resultLay->setContentsMargins(0, 30, 0, 0);
+
+ iconLabel = new QLabel(this);
+ iconLabel->setFixedSize(64, 64);
+ resultLay->addWidget(iconLabel, 0, Qt::AlignCenter);
+
+ resultMsg = new QLabel(this);
+ resultLay->addWidget(resultMsg, 0, Qt::AlignCenter);
+
+ warningLabel = new QLabel(this);
+ resultLay->addWidget(warningLabel);
+ QPalette pal = warningLabel->palette();
+ pal.setColor(QPalette::WindowText, QColor("red"));
+ warningLabel->setPalette(pal);
+ warningLabel->setWordWrap(true);
+ warningLabel->setAlignment(Qt::AlignLeft);
+ warningLabel->setVisible(false);
+
+ mainLay->addWidget(progressPage);
+ mainLay->addWidget(resultPage);
+}
+
+bool EncryptProgressDialog::validateExportPath(const QString &path, QString *msg)
+{
+ auto setMsg = [&](const QString &info) { if (msg) *msg = info; };
+ if (path.isEmpty()) {
+ setMsg(tr("Recovery key export path cannot be empty!"));
+ return false;
+ }
+
+ if (!QDir(path).exists()) {
+ setMsg(tr("Recovery key export path is not exists!"));
+ return false;
+ }
+
+ QStorageInfo storage(path);
+ if (storage.isReadOnly()) {
+ setMsg(tr("This partition is read-only, please export to a writable "
+ "partition"));
+ return false;
+ }
+
+ using namespace dfmmount;
+ auto monitor = DDeviceManager::instance()->getRegisteredMonitor(DeviceType::kBlockDevice).objectCast();
+ Q_ASSERT(monitor);
+ auto devObjPaths = monitor->resolveDeviceNode(storage.device(), {});
+ if (!devObjPaths.isEmpty()) {
+ auto objPath = devObjPaths.constFirst();
+ auto devPtr = monitor->createDeviceById(objPath);
+ if (devPtr && devPtr->getProperty(Property::kBlockCryptoBackingDevice).toString() != "/") {
+ setMsg(tr("The partition is encrypted, please export to a non-encrypted "
+ "partition or external device such as a USB flash drive."));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void EncryptProgressDialog::saveRecKey(const QString &path)
+{
+ QString recFileName = QString("%1/%2_recovery_key.txt")
+ .arg(path)
+ .arg(device.mid(5));
+ QFile f(recFileName);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ dialog_utils::showDialog(tr("Error"), tr("Cannot create recovery key file!"), dialog_utils::DialogType::kError);
+ return;
+ }
+ f.write(recKey.toLocal8Bit());
+ f.close();
+ accept();
+ qInfo() << "recovery key has been wrote to" << recFileName;
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptprogressdialog.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptprogressdialog.h
new file mode 100644
index 0000000000..bda64babdc
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/encryptprogressdialog.h
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef ENCRYPTPROGRESSDIALOG_H
+#define ENCRYPTPROGRESSDIALOG_H
+
+#include
+#include
+
+DWIDGET_USE_NAMESPACE
+
+class QStackedLayout;
+
+namespace dfmplugin_diskenc {
+
+class EncryptProgressDialog : public DDialog
+{
+ Q_OBJECT
+public:
+ explicit EncryptProgressDialog(QWidget *parent = nullptr);
+ void setText(const QString &title, const QString &message);
+ void updateProgress(double progress);
+ void showResultPage(bool success, const QString &title, const QString &message);
+ void showExportPage();
+ inline void setRecoveryKey(const QString &key, const QString &device)
+ {
+ recKey = key;
+ this->device = device;
+ }
+
+protected Q_SLOTS:
+ void onCicked(int idx, const QString &btnTxt);
+
+protected:
+ void initUI();
+ bool validateExportPath(const QString &path, QString *msg);
+ void saveRecKey(const QString &path);
+
+private:
+ DWaterProgress *progress { nullptr };
+ QLabel *message { nullptr };
+ QStackedLayout *mainLay { nullptr };
+ QLabel *iconLabel { nullptr };
+ QLabel *resultMsg { nullptr };
+ QLabel *warningLabel { nullptr };
+
+ QString recKey;
+ QString device;
+};
+}
+
+#endif // ENCRYPTPROGRESSDIALOG_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/unlockpartitiondialog.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/unlockpartitiondialog.cpp
new file mode 100644
index 0000000000..8b865bc06a
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/unlockpartitiondialog.cpp
@@ -0,0 +1,144 @@
+// SPDX-FileCopyrightText: 2020 - 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "unlockpartitiondialog.h"
+#include "utils/encryptutils.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace dfmplugin_diskenc;
+DWIDGET_USE_NAMESPACE
+
+UnlockPartitionDialog::UnlockPartitionDialog(UnlockType type, QWidget *parent)
+ : DDialog(parent),
+ currType(type),
+ initType(type)
+{
+ setModal(true);
+ initUI();
+ initConnect();
+ if (dialog_utils::isWayland())
+ setWindowFlag(Qt::WindowStaysOnTopHint);
+}
+
+UnlockPartitionDialog::~UnlockPartitionDialog()
+{
+}
+
+void UnlockPartitionDialog::initUI()
+{
+ setIcon(QIcon::fromTheme("drive-harddisk-root"));
+
+ QFrame *content = new QFrame;
+ passwordLineEdit = new DPasswordEdit;
+ chgUnlockType = new DCommandLinkButton("");
+
+ QVBoxLayout *mainLayout = new QVBoxLayout;
+ mainLayout->addSpacing(10);
+ mainLayout->addWidget(passwordLineEdit);
+ mainLayout->addWidget(chgUnlockType, 0, Qt::AlignRight);
+ mainLayout->addSpacing(10);
+ content->setLayout(mainLayout);
+ addContent(content);
+
+ addButton(tr("Cancel"));
+ addButton(tr("Unlock"), true, DDialog::ButtonRecommend);
+ auto unlockBtn = getButton(1);
+ if (unlockBtn) unlockBtn->setEnabled(false);
+
+ updateUserHint();
+ setOnButtonClickedClose(false);
+
+ if (initType == kRec)
+ chgUnlockType->setVisible(false);
+}
+
+void UnlockPartitionDialog::initConnect()
+{
+ connect(this, &DDialog::buttonClicked, this, &UnlockPartitionDialog::handleButtonClicked);
+ connect(chgUnlockType, &DCommandLinkButton::clicked, this, &UnlockPartitionDialog::switchUnlockType);
+ connect(passwordLineEdit, &DPasswordEdit::textChanged, this, [this](const QString &txt) {
+ QString newText = txt;
+ QSignalBlocker blocker(sender());
+ if (currType == kRec) {
+ newText = recovery_key_utils::formatRecoveryKey(newText);
+ passwordLineEdit->setText(newText);
+ }
+ auto unlockBtn = getButton(1);
+ if (unlockBtn) unlockBtn->setEnabled(newText.length() != 0);
+ });
+}
+
+void UnlockPartitionDialog::updateUserHint()
+{
+ setTitle(tr("Unlock encryption partition"));
+ passwordLineEdit->setEchoMode(QLineEdit::Password);
+ passwordLineEdit->setEchoButtonIsVisible(true);
+
+ chgUnlockType->setText(tr("Unlock by recovery key"));
+ switch (currType) {
+ case kRec: {
+ setTitle(tr("Unlock by recovery key"));
+ QString text = (initType == kPwd)
+ ? tr("Unlock by passphrase")
+ : tr("Unlock by PIN");
+ chgUnlockType->setText(text);
+ passwordLineEdit->setPlaceholderText(tr("Please input recovery key to unlock device"));
+ passwordLineEdit->setEchoMode(QLineEdit::Normal);
+ passwordLineEdit->setEchoButtonIsVisible(false);
+ break;
+ }
+ case kPwd:
+ passwordLineEdit->setPlaceholderText(tr("Please input passphrase to unlock device"));
+ break;
+ case kPin:
+ passwordLineEdit->setPlaceholderText(tr("Please input PIN to unlock device"));
+ break;
+ }
+}
+
+void UnlockPartitionDialog::handleButtonClicked(int index, QString text)
+{
+ Q_UNUSED(text)
+ if (index == 1) {
+ key = passwordLineEdit->text();
+ if (currType == kRec) {
+ key.remove("-");
+ if (key.length() != 24) {
+ passwordLineEdit->showAlertMessage(tr("Recovery key is not valid!"));
+ return;
+ }
+ }
+ accept();
+ return;
+ }
+ reject();
+}
+
+void UnlockPartitionDialog::switchUnlockType()
+{
+ if (currType == kRec)
+ currType = initType;
+ else if (currType == kPin || currType == kPwd)
+ currType = kRec;
+ passwordLineEdit->clear();
+ updateUserHint();
+}
+
+void UnlockPartitionDialog::showEvent(QShowEvent *event)
+{
+ passwordLineEdit->setFocus();
+ DDialog::showEvent(event);
+}
+
+QPair UnlockPartitionDialog::getUnlockKey() const
+{
+ return { currType, key };
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/unlockpartitiondialog.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/unlockpartitiondialog.h
new file mode 100644
index 0000000000..a7c2ccc4cc
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/gui/unlockpartitiondialog.h
@@ -0,0 +1,52 @@
+// SPDX-FileCopyrightText: 2020 - 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef MOUNTSECRETDISKASKPASSWORDDIALOG_H
+#define MOUNTSECRETDISKASKPASSWORDDIALOG_H
+
+#include
+
+class QLineEdit;
+class QLabel;
+
+DWIDGET_BEGIN_NAMESPACE
+class DPasswordEdit;
+class DCommandLinkButton;
+DWIDGET_END_NAMESPACE
+
+namespace dfmplugin_diskenc {
+class UnlockPartitionDialog : public DTK_WIDGET_NAMESPACE::DDialog
+{
+ Q_OBJECT
+public:
+ enum UnlockType {
+ kPwd,
+ kPin,
+ kRec
+ };
+ explicit UnlockPartitionDialog(UnlockType type, QWidget *parent = nullptr);
+ ~UnlockPartitionDialog();
+
+ QPair getUnlockKey() const;
+
+protected Q_SLOTS:
+ void handleButtonClicked(int index, QString text);
+ void switchUnlockType();
+ void updateUserHint();
+
+protected:
+ void showEvent(QShowEvent *event);
+ void initUI();
+ void initConnect();
+
+private:
+ DTK_WIDGET_NAMESPACE::DPasswordEdit *passwordLineEdit = nullptr;
+ Dtk::Widget::DCommandLinkButton *chgUnlockType = nullptr;
+ QString key = "";
+ UnlockType currType { kPin };
+ UnlockType initType { kPin };
+};
+}
+
+#endif // MOUNTSECRETDISKASKPASSWORDDIALOG_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/menu/diskencryptmenuscene.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/menu/diskencryptmenuscene.cpp
new file mode 100644
index 0000000000..a8d3b12b25
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/menu/diskencryptmenuscene.cpp
@@ -0,0 +1,669 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "dfmplugin_disk_encrypt_global.h"
+#include "diskencryptmenuscene.h"
+#include "gui/encryptparamsinputdialog.h"
+#include "gui/decryptparamsinputdialog.h"
+#include "gui/chgpassphrasedialog.h"
+#include "events/eventshandler.h"
+#include "utils/encryptutils.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+DFMBASE_USE_NAMESPACE
+using namespace dfmplugin_diskenc;
+using namespace disk_encrypt;
+
+static constexpr char kActIDEncrypt[] { "de_0_encrypt" };
+static constexpr char kActIDResumeEncrypt[] { "de_0_resumeEncrypt" };
+static constexpr char kActIDUnlock[] { "de_0_unlock" };
+static constexpr char kActIDDecrypt[] { "de_1_decrypt" };
+static constexpr char kActIDResumeDecrypt[] { "de_1_resumeDecrypt" };
+static constexpr char kActIDChangePwd[] { "de_2_changePwd" };
+
+DiskEncryptMenuScene::DiskEncryptMenuScene(QObject *parent)
+ : AbstractMenuScene(parent)
+{
+}
+
+dfmbase::AbstractMenuScene *DiskEncryptMenuCreator::create()
+{
+ return new DiskEncryptMenuScene();
+}
+
+QString DiskEncryptMenuScene::name() const
+{
+ return DiskEncryptMenuCreator::name();
+}
+
+bool DiskEncryptMenuScene::initialize(const QVariantHash ¶ms)
+{
+ if (!config_utils::enableEncrypt()) {
+ qInfo() << "partition encryption feature is disabled.";
+ return false;
+ }
+
+ QList selectedItems = params.value(MenuParamKey::kSelectFiles).value>();
+ if (selectedItems.isEmpty())
+ return false;
+
+ auto selectedItem = selectedItems.first();
+ if (!selectedItem.path().endsWith("blockdev"))
+ return false;
+
+ QSharedPointer info = InfoFactory::create(selectedItem);
+ if (!info)
+ return false;
+ info->refresh();
+
+ selectedItemInfo = info->extraProperties();
+ auto device = selectedItemInfo.value("Device", "").toString();
+ if (device.isEmpty())
+ return false;
+
+ const QString &idType = selectedItemInfo.value("IdType").toString();
+ auto preferDev = selectedItemInfo.value("PreferredDevice", "").toString();
+ if (device.startsWith("/dev/dm-") && idType != "crypto_LUKS") {
+ qInfo() << "mapper device is not supported to be encrypted yet." << device << preferDev;
+ return false;
+ }
+
+ const QStringList &supportedFS { "ext4", "ext3", "ext2" };
+ if (idType == "crypto_LUKS") {
+ if (selectedItemInfo.value("IdVersion").toString() == "1")
+ return false;
+ hasCryptHeader = true;
+ } else if (!supportedFS.contains(idType)) {
+ return false;
+ }
+
+ QString devMpt = selectedItemInfo.value("MountPoint", "").toString();
+ if (devMpt.isEmpty() && selectedItemInfo.contains("ClearBlockDeviceInfo"))
+ devMpt = selectedItemInfo.value("ClearBlockDeviceInfo").toHash().value("MountPoint").toString();
+
+ if (kDisabledEncryptPath.contains(devMpt, Qt::CaseInsensitive)) {
+ qInfo() << devMpt << "doesn't support encrypt";
+ return false;
+ }
+
+ param.devID = selectedItemInfo.value("Id").toString();
+ param.devDesc = device;
+ param.initOnly = fstab_utils::isFstabItem(devMpt);
+ param.mountPoint = devMpt;
+ param.uuid = selectedItemInfo.value("IdUUID", "").toString();
+ param.deviceDisplayName = info->displayOf(dfmbase::FileInfo::kFileDisplayName);
+ param.type = SecKeyType::kPasswordOnly;
+ param.backingDevUUID = param.uuid;
+ param.isDetachedHeader = false;
+
+ QVariantHash clearInfo = selectedItemInfo.value("ClearBlockDeviceInfo").toHash();
+ if (!clearInfo.isEmpty()) {
+ param.clearDevUUID = clearInfo.value("IdUUID", "").toString();
+ param.prefferDevName = clearInfo.value("PreferredDevice").toString().mid(12); // /dev/mapper/xxxx ==> xxxx
+ }
+
+ if (hasCryptHeader)
+ param.type = static_cast(device_utils::encKeyType(device));
+
+ return true;
+}
+
+bool DiskEncryptMenuScene::create(QMenu *)
+{
+ QAction *act = nullptr;
+
+ act = new QAction(tr("Unlock encrypted partition"));
+ act->setProperty(ActionPropertyKey::kActionID, kActIDUnlock);
+ actions.insert(kActIDUnlock, act);
+
+ act = new QAction(tr("Cancel partition encryption"));
+ act->setProperty(ActionPropertyKey::kActionID, kActIDDecrypt);
+ actions.insert(kActIDDecrypt, act);
+
+ QString keyType = (param.type == kTPMAndPIN) ? "PIN" : tr("passphrase");
+ act = new QAction(tr("Changing the encryption %1").arg(keyType));
+ act->setProperty(ActionPropertyKey::kActionID, kActIDChangePwd);
+ actions.insert(kActIDChangePwd, act);
+
+ act = new QAction(tr("Continue partition encryption"));
+ act->setProperty(ActionPropertyKey::kActionID, kActIDResumeEncrypt);
+ actions.insert(kActIDResumeEncrypt, act);
+
+ act = new QAction(tr("Continue partition decryption"));
+ act->setProperty(ActionPropertyKey::kActionID, kActIDResumeDecrypt);
+ actions.insert(kActIDResumeDecrypt, act);
+
+ act = new QAction(tr("Enable partition encryption"));
+ act->setProperty(ActionPropertyKey::kActionID, kActIDEncrypt);
+ actions.insert(kActIDEncrypt, act);
+
+ return true;
+}
+
+bool DiskEncryptMenuScene::triggered(QAction *action)
+{
+ QString actID = action->property(ActionPropertyKey::kActionID).toString();
+
+ if (actID == kActIDEncrypt) {
+ encryptDevice(param);
+ } else if (actID == kActIDResumeEncrypt) {
+ EventsHandler::instance()->resumeEncrypt(param.devDesc);
+ } else if (actID == kActIDDecrypt || actID == kActIDResumeDecrypt) {
+ QString displayName = QString("%1(%2)").arg(param.deviceDisplayName).arg(param.devDesc.mid(5));
+ if (dialog_utils::showConfirmDecryptionDialog(displayName, param.initOnly) != QDialog::Accepted)
+ return true;
+ param.initOnly ? doDecryptDevice(param) : unmountBefore(decryptDevice, param);
+ } else if (actID == kActIDChangePwd) {
+ changePassphrase(param);
+ } else if (actID == kActIDUnlock) {
+ unlockDevice(selectedItemInfo.value("Id").toString());
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void DiskEncryptMenuScene::updateState(QMenu *parent)
+{
+ sortActions(parent);
+ updateActions();
+}
+
+void DiskEncryptMenuScene::encryptDevice(const DeviceEncryptParam ¶m)
+{
+ QString displayName = QString("%1(%2)").arg(param.deviceDisplayName).arg(param.devDesc.mid(5));
+ bool needreboot = param.isDetachedHeader ? false : param.initOnly;
+ int ret = dialog_utils::showConfirmEncryptionDialog(displayName, needreboot);
+ if (ret == QDialog::Accepted) {
+ if (param.initOnly)
+ doEncryptDevice(param);
+ else
+ unmountBefore(doEncryptDevice, param);
+ }
+}
+
+void DiskEncryptMenuScene::decryptDevice(const DeviceEncryptParam ¶m)
+{
+ auto inputs = param;
+ if (inputs.type == kTPMOnly) {
+ QString passphrase = tpm_passphrase_utils::getPassphraseFromTPM_NonBlock(inputs.devDesc, "");
+ inputs.key = passphrase;
+ if (passphrase.isEmpty()) {
+ dialog_utils::showDialog(tr("Error"),
+ tr("Cannot resolve passphrase from TPM"),
+ dialog_utils::DialogType::kError);
+ return;
+ }
+ doDecryptDevice(inputs);
+ return;
+ }
+
+ DecryptParamsInputDialog dlg(inputs.devDesc);
+ if (inputs.type == kTPMAndPIN)
+ dlg.setInputPIN(true);
+
+ if (dlg.exec() != QDialog::Accepted)
+ return;
+
+ qDebug() << "start decrypting device" << inputs.devDesc;
+ inputs.key = dlg.getKey();
+ if (dlg.usingRecKey() || inputs.type == kPasswordOnly)
+ doDecryptDevice(inputs);
+ else {
+ inputs.key = tpm_passphrase_utils::getPassphraseFromTPM_NonBlock(inputs.devDesc, inputs.key);
+ if (inputs.key.isEmpty()) {
+ dialog_utils::showDialog(tr("Error"), tr("PIN error"), dialog_utils::DialogType::kError);
+ return;
+ }
+ doDecryptDevice(inputs);
+ }
+}
+
+void DiskEncryptMenuScene::changePassphrase(DeviceEncryptParam param)
+{
+ QString dev = param.devDesc;
+ ChgPassphraseDialog dlg(param.devDesc);
+ if (dlg.exec() != 1)
+ return;
+
+ auto inputs = dlg.getPassphrase();
+ QString oldKey = inputs.first;
+ QString newKey = inputs.second;
+ if (param.type == SecKeyType::kTPMAndPIN) {
+ if (!dlg.validateByRecKey()) {
+ oldKey = tpm_passphrase_utils::getPassphraseFromTPM_NonBlock(dev, oldKey);
+ if (oldKey.isEmpty()) {
+ dialog_utils::showDialog(tr("Error"), tr("PIN error"), dialog_utils::DialogType::kError);
+ return;
+ }
+ }
+ QString newPassphrase;
+ int ret = tpm_passphrase_utils::genPassphraseFromTPM_NonBlock(dev, newKey, &newPassphrase);
+ if (ret != tpm_passphrase_utils::kTPMNoError) {
+ dialog_utils::showTPMError(tr("Change passphrase failed"), static_cast(ret));
+ return;
+ }
+ newKey = newPassphrase;
+ }
+ param.validateByRecKey = dlg.validateByRecKey();
+ param.key = oldKey;
+ param.newKey = newKey;
+ doChangePassphrase(param);
+}
+
+void DiskEncryptMenuScene::unlockDevice(const QString &devObjPath)
+{
+ auto blkDev = device_utils::createBlockDevice(devObjPath);
+ if (!blkDev)
+ return;
+
+ QString pwd;
+ bool cancel { false };
+ bool ok = EventsHandler::instance()->onAcquireDevicePwd(blkDev->device(), &pwd, &cancel);
+ if (pwd.isEmpty() && ok) {
+ qWarning() << "acquire pwd faield!!!";
+ return;
+ }
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ blkDev->unlockAsync(pwd, {}, onUnlocked);
+}
+
+void DiskEncryptMenuScene::doEncryptDevice(const DeviceEncryptParam ¶m)
+{
+ // if tpm selected, use tpm to generate the key
+ QString tpmConfig, tpmToken;
+ if (param.type != kPasswordOnly) {
+ tpmConfig = generateTPMConfig();
+ tpmToken = generateTPMToken(param.devDesc, param.type == kTPMAndPIN);
+ }
+
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ if (iface.isValid()) {
+ auto blkDev = device_utils::createBlockDevice(param.devID);
+ if (!blkDev) {
+ qCritical() << "Create block device failed, the object is: " << param.devID;
+ return;
+ }
+ QString partUuid { blkDev->getProperty(dfmmount::Property::kPartitionUUID).toString() };
+ QVariantMap params {
+ { encrypt_param_keys::kKeyDevice, param.devDesc },
+ { encrypt_param_keys::kKeyUUID, param.uuid },
+ { encrypt_param_keys::kKeyCipher, config_utils::cipherType() },
+ { encrypt_param_keys::kKeyPassphrase, encryptPasswd(param.key) },
+ { encrypt_param_keys::kKeyInitParamsOnly, param.isDetachedHeader ? false : param.initOnly },
+ { encrypt_param_keys::kKeyRecoveryExportPath, param.exportPath },
+ { encrypt_param_keys::kKeyEncMode, static_cast(param.type) },
+ { encrypt_param_keys::kKeyDeviceName, param.deviceDisplayName },
+ { encrypt_param_keys::kKeyMountPoint, param.mountPoint },
+ { encrypt_param_keys::kKeyIsDetachedHeader, param.isDetachedHeader },
+ { encrypt_param_keys::kKeyPrefferDevice, param.prefferDevName },
+ { encrypt_param_keys::kKeyClearDevUUID, param.clearDevUUID },
+ { encrypt_param_keys::kKeyPartUUID, partUuid }
+ };
+ if (!tpmConfig.isEmpty()) params.insert(encrypt_param_keys::kKeyTPMConfig, tpmConfig);
+ if (!tpmToken.isEmpty()) params.insert(encrypt_param_keys::kKeyTPMToken, tpmToken);
+
+ QDBusReply reply = iface.call("PrepareEncryptDisk", params);
+ qDebug() << "preencrypt device jobid:" << reply.value();
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ }
+}
+
+void DiskEncryptMenuScene::doReencryptDevice(const DeviceEncryptParam ¶m)
+{
+ // if tpm selected, use tpm to generate the key
+ QString tpmConfig, tpmToken;
+ if (param.type != kPasswordOnly) {
+ tpmConfig = generateTPMConfig();
+ tpmToken = generateTPMToken(param.devDesc, param.type == kTPMAndPIN);
+ }
+
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ if (iface.isValid()) {
+ QVariantMap params {
+ { encrypt_param_keys::kKeyDevice, param.devDesc },
+ { encrypt_param_keys::kKeyUUID, param.uuid },
+ { encrypt_param_keys::kKeyCipher, config_utils::cipherType() },
+ { encrypt_param_keys::kKeyPassphrase, encryptPasswd(param.key) },
+ { encrypt_param_keys::kKeyInitParamsOnly, param.initOnly },
+ { encrypt_param_keys::kKeyRecoveryExportPath, param.exportPath },
+ { encrypt_param_keys::kKeyEncMode, static_cast(param.type) },
+ { encrypt_param_keys::kKeyDeviceName, param.deviceDisplayName },
+ { encrypt_param_keys::kKeyMountPoint, param.mountPoint },
+ { encrypt_param_keys::kKeyBackingDevUUID, param.backingDevUUID },
+ { encrypt_param_keys::kKeyClearDevUUID, param.clearDevUUID }
+ };
+ if (!tpmConfig.isEmpty()) params.insert(encrypt_param_keys::kKeyTPMConfig, tpmConfig);
+ if (!tpmToken.isEmpty()) params.insert(encrypt_param_keys::kKeyTPMToken, tpmToken);
+
+ QDBusReply reply = iface.call("SetEncryptParams", params);
+ qDebug() << "start reencrypt device";
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ }
+}
+
+void DiskEncryptMenuScene::doDecryptDevice(const DeviceEncryptParam ¶m)
+{
+ // if tpm selected, use tpm to generate the key
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ if (iface.isValid()) {
+ QVariantMap params {
+ { encrypt_param_keys::kKeyDevice, param.devDesc },
+ { encrypt_param_keys::kKeyPassphrase, encryptPasswd(param.key) },
+ { encrypt_param_keys::kKeyInitParamsOnly, param.initOnly },
+ { encrypt_param_keys::kKeyUUID, param.uuid },
+ { encrypt_param_keys::kKeyDeviceName, param.deviceDisplayName },
+ { encrypt_param_keys::kKeyPrefferDevice, param.prefferDevName },
+ { encrypt_param_keys::kKeyClearDevUUID, param.clearDevUUID }
+ };
+ QDBusReply reply = iface.call("DecryptDisk", params);
+ qDebug() << "preencrypt device jobid:" << reply.value();
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+
+ EventsHandler::instance()->autoStartDFM();
+ }
+}
+
+void DiskEncryptMenuScene::doChangePassphrase(const DeviceEncryptParam ¶m)
+{
+ QString token;
+ if (param.type != SecKeyType::kPasswordOnly) {
+ // new tpm token should be setted.
+ QFile f(kGlobalTPMConfigPath + param.devDesc + "/token.json");
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning() << "cannot read old tpm token!!!";
+ return;
+ }
+ QJsonDocument oldTokenDoc = QJsonDocument::fromJson(f.readAll());
+ f.close();
+ QJsonObject oldTokenObj = oldTokenDoc.object();
+
+ QString newToken = generateTPMToken(param.devDesc, param.type == SecKeyType::kTPMAndPIN);
+ QJsonDocument newTokenDoc = QJsonDocument::fromJson(newToken.toLocal8Bit());
+ QJsonObject newTokenObj = newTokenDoc.object();
+
+ oldTokenObj.insert("enc", newTokenObj.value("enc"));
+ oldTokenObj.insert("kek-priv", newTokenObj.value("kek-priv"));
+ oldTokenObj.insert("kek-pub", newTokenObj.value("kek-pub"));
+ oldTokenObj.insert("iv", newTokenObj.value("iv"));
+ newTokenDoc.setObject(oldTokenObj);
+ token = newTokenDoc.toJson(QJsonDocument::Compact);
+ }
+
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ if (iface.isValid()) {
+ QVariantMap params {
+ { encrypt_param_keys::kKeyDevice, param.devDesc },
+ { encrypt_param_keys::kKeyPassphrase, encryptPasswd(param.newKey) },
+ { encrypt_param_keys::kKeyOldPassphrase, encryptPasswd(param.key) },
+ { encrypt_param_keys::kKeyValidateWithRecKey, param.validateByRecKey },
+ { encrypt_param_keys::kKeyTPMToken, token },
+ { encrypt_param_keys::kKeyDeviceName, param.deviceDisplayName }
+ };
+ QDBusReply reply = iface.call("ChangeEncryptPassphress", params);
+ qDebug() << "modify device passphrase jobid:" << reply.value();
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ }
+}
+
+QString DiskEncryptMenuScene::generateTPMConfig()
+{
+ QString sessionHashAlgo, sessionKeyAlgo, primaryHashAlgo, primaryKeyAlgo, minorHashAlgo, minorKeyAlgo;
+ if (!tpm_passphrase_utils::getAlgorithm(&sessionHashAlgo, &sessionKeyAlgo, &primaryHashAlgo, &primaryKeyAlgo, &minorHashAlgo, &minorKeyAlgo)) {
+ qWarning() << "cannot choose algorithm for tpm";
+ primaryHashAlgo = "sha256";
+ primaryKeyAlgo = "ecc";
+ }
+
+ QJsonObject tpmParams;
+ tpmParams = { { "keyslot", "1" },
+ { "session-key-alg", sessionKeyAlgo },
+ { "session-hash-alg", sessionHashAlgo },
+ { "primary-key-alg", primaryKeyAlgo },
+ { "primary-hash-alg", primaryHashAlgo },
+ { "pcr", "7" },
+ { "pcr-bank", primaryHashAlgo } };
+ return QJsonDocument(tpmParams).toJson();
+}
+
+QString DiskEncryptMenuScene::generateTPMToken(const QString &device, bool pin)
+{
+ QString tpmConfig = generateTPMConfig();
+ QJsonDocument doc = QJsonDocument::fromJson(tpmConfig.toLocal8Bit());
+ QJsonObject token = doc.object();
+
+ // keep same with usec.
+ // https://gerrit.uniontech.com/plugins/gitiles/usec-crypt-kit/+/refs/heads/master/src/boot-crypt/util.cpp
+ // j["type"] = "usec-tpm2";
+ // j["keyslots"] = {"0"};
+ // j["kek-priv"] = encoded_priv_key;
+ // j["kek-pub"] = encoded_pub_key;
+ // j["primary-key-alg"] = primary_key_alg;
+ // j["primary-hash-alg"] = primary_hash_alg;
+ // j["iv"] = encoded_iv;
+ // j["enc"] = encoded_cipher;
+ // j["pin"] = pin;
+ // j["pcr"] = pcr;
+ // j["pcr-bank"] = pcr_bank;
+
+ token.remove("keyslot");
+ token.insert("type", "usec-tpm2");
+ token.insert("keyslots", QJsonArray::fromStringList({ "0" }));
+ token.insert("kek-priv", getBase64Of(kGlobalTPMConfigPath + device + "/key.priv"));
+ token.insert("kek-pub", getBase64Of(kGlobalTPMConfigPath + device + "/key.pub"));
+ token.insert("iv", getBase64Of(kGlobalTPMConfigPath + device + "/iv.bin"));
+ token.insert("enc", getBase64Of(kGlobalTPMConfigPath + device + "/cipher.out"));
+ token.insert("pin", pin ? "1" : "0");
+
+ doc.setObject(token);
+ return doc.toJson(QJsonDocument::Compact);
+}
+
+QString DiskEncryptMenuScene::getBase64Of(const QString &fileName)
+{
+ QFile f(fileName);
+ if (!f.open(QIODevice::ReadOnly)) {
+ qDebug() << "cannot read file of" << fileName;
+ return "";
+ }
+ QByteArray contents = f.readAll();
+ f.close();
+ return QString(contents.toBase64());
+}
+
+void DiskEncryptMenuScene::onUnlocked(bool ok, dfmmount::OperationErrorInfo info, QString clearDev)
+{
+ QApplication::restoreOverrideCursor();
+ if (!ok && info.code != dfmmount::DeviceError::kUDisksErrorNotAuthorizedDismissed) {
+ qWarning() << "unlock device failed!" << info.message;
+ dialog_utils::showDialog(tr("Unlock device failed"),
+ tr("Wrong passphrase"),
+ dialog_utils::kError);
+ return;
+ }
+
+ auto dev = device_utils::createBlockDevice(clearDev);
+ if (!dev)
+ return;
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+ dev->mountAsync({}, onMounted);
+}
+
+void DiskEncryptMenuScene::onMounted(bool ok, dfmmount::OperationErrorInfo info, QString mountPoint)
+{
+ QApplication::restoreOverrideCursor();
+ if (!ok && info.code != dfmmount::DeviceError::kUDisksErrorNotAuthorizedDismissed) {
+ qWarning() << "mount device failed!" << info.message;
+ dialog_utils::showDialog(tr("Mount device failed"), "", dialog_utils::kError);
+ return;
+ }
+}
+
+void DiskEncryptMenuScene::unmountBefore(const std::function &after, const DeviceEncryptParam ¶m)
+{
+ using namespace dfmmount;
+ auto blk = device_utils::createBlockDevice(param.devID);
+ if (!blk)
+ return;
+
+ auto _params = param;
+ if (blk->isEncrypted()) {
+ const QString &clearPath = blk->getProperty(Property::kEncryptedCleartextDevice).toString();
+ if (clearPath.length() > 1) {
+ auto lock = [=] {
+ blk->lockAsync({}, [=](bool ok, OperationErrorInfo err) {
+ ok ? after(_params) : onUnmountError(kLock, _params.devDesc, err);
+ });
+ };
+ auto onUnmounted = [=](bool ok, const OperationErrorInfo &err) {
+ ok ? lock() : onUnmountError(kUnmount, _params.devDesc, err);
+ };
+
+ // do unmount cleardev
+ auto clearDev = device_utils::createBlockDevice(clearPath);
+ clearDev->unmountAsync({}, onUnmounted);
+ } else {
+ after(_params);
+ }
+ } else {
+ blk->unmountAsync({}, [=](bool ok, OperationErrorInfo err) {
+ ok ? after(_params) : onUnmountError(kUnmount, _params.devDesc, err);
+ });
+ }
+}
+
+void DiskEncryptMenuScene::onUnmountError(OpType t, const QString &dev, const dfmmount::OperationErrorInfo &err)
+{
+ qDebug() << "unmount device failed:"
+ << dev
+ << err.message;
+ QString operation = (t == kUnmount) ? tr("unmount") : tr("lock");
+ dialog_utils::showDialog(tr("Encrypt failed"),
+ tr("Cannot %1 device %2").arg(operation, dev),
+ dialog_utils::kError);
+}
+
+void DiskEncryptMenuScene::sortActions(QMenu *parent)
+{
+ Q_ASSERT(parent);
+ QList acts = parent->actions();
+ QAction *before { acts.last() };
+ for (int i = 0; i < acts.count(); ++i) {
+ auto act = acts.at(i);
+ QString actID = act->property(ActionPropertyKey::kActionID).toString();
+ if (actID == "computer-rename" // the encrypt actions should be under computer-rename
+ && (i + 1) < acts.count()) {
+ before = acts.at(i + 1);
+ break;
+ }
+ }
+
+ std::for_each(actions.begin(), actions.end(), [=](QAction *act) {
+ parent->insertAction(before, act);
+ act->setParent(parent);
+ });
+}
+
+void DiskEncryptMenuScene::updateActions()
+{
+ std::for_each(actions.begin(), actions.end(), [](QAction *act) {
+ act->setVisible(false);
+ act->setEnabled(false);
+ });
+
+ // update operatable
+ bool taskWorking = EventsHandler::instance()->isTaskWorking();
+ bool currDevOperating = EventsHandler::instance()->isUnderOperating(param.devDesc);
+ bool hasPendingJob = EventsHandler::instance()->hasPendingTask();
+ actions[kActIDEncrypt]->setEnabled(!taskWorking && !hasPendingJob);
+ actions[kActIDDecrypt]->setEnabled(!taskWorking && !hasPendingJob && !currDevOperating);
+ actions[kActIDChangePwd]->setEnabled(!taskWorking);
+ actions[kActIDResumeEncrypt]->setEnabled(!taskWorking && !currDevOperating);
+ actions[kActIDResumeDecrypt]->setEnabled(!taskWorking && !currDevOperating);
+ actions[kActIDUnlock]->setEnabled(!currDevOperating);
+
+ // update visibility
+ if (hasCryptHeader) {
+ int states = EventsHandler::instance()->deviceEncryptStatus(param.devDesc);
+ // fully encrypted
+ if (states & kStatusFinished) {
+ bool unlocked = selectedItemInfo.value("CleartextDevice").toString() != "/";
+ actions[kActIDDecrypt]->setVisible(true);
+ actions[kActIDUnlock]->setVisible(!unlocked);
+ if (param.type != disk_encrypt::kTPMOnly)
+ actions[kActIDChangePwd]->setVisible(true);
+ }
+ // not finished
+ else if (states & kStatusOnline) {
+ // encrytp not finish
+ if (states & kStatusEncrypt) {
+ if (states & kStatusNoEncryptConfig) {
+ param.isDetachedHeader = true;
+ actions[kActIDEncrypt]->setVisible(true);
+ } else {
+ param.isDetachedHeader = false;
+ actions[kActIDResumeEncrypt]->setVisible(true);
+ }
+ }
+ // decrypt not finish
+ else if (states & kStatusDecrypt) {
+ actions[kActIDDecrypt]->setVisible(false);
+ actions[kActIDResumeDecrypt]->setVisible(true);
+ }
+ } else {
+ qWarning() << "unmet status!" << param.devDesc << states;
+ }
+ } else if (EventsHandler::instance()->unfinishedDecryptJob() == param.devDesc) {
+ actions[kActIDResumeDecrypt]->setVisible(true);
+ } else {
+ actions[kActIDEncrypt]->setVisible(true);
+ }
+
+ QString dev = param.devDesc;
+ QString fileName = kRebootFlagFilePrefix + dev.replace("/", "_");
+ QFile rebootFlag(fileName);
+ if (rebootFlag.exists()) {
+ actions[kActIDEncrypt]->setText(tr("Reboot to continue encrypt"));
+ actions[kActIDDecrypt]->setText(tr("Reboot to finish decrypt"));
+ }
+}
+
+QString DiskEncryptMenuScene::encryptPasswd(const QString &passwd)
+{
+ QByteArray byteArray = passwd.toUtf8();
+ QByteArray encodedByteArray = byteArray.toBase64();
+ return QString::fromUtf8(encodedByteArray);
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/menu/diskencryptmenuscene.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/menu/diskencryptmenuscene.h
new file mode 100644
index 0000000000..a9ec419f46
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/menu/diskencryptmenuscene.h
@@ -0,0 +1,85 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef DISKENCRYPTMENUSCENE_H
+#define DISKENCRYPTMENUSCENE_H
+
+#include "gui/encryptparamsinputdialog.h"
+
+#include
+#include
+
+#include
+
+#include
+
+class QAction;
+
+namespace dfmplugin_diskenc {
+
+class DiskEncryptMenuCreator : public dfmbase::AbstractSceneCreator
+{
+ Q_OBJECT
+ // AbstractSceneCreator interface
+public:
+ virtual dfmbase::AbstractMenuScene *create() override;
+ static inline QString name()
+ {
+ return "DiskEncryptMenu";
+ }
+};
+
+class DiskEncryptMenuScene : public dfmbase::AbstractMenuScene
+{
+ Q_OBJECT
+public:
+ explicit DiskEncryptMenuScene(QObject *parent = nullptr);
+
+ // AbstractMenuScene interface
+public:
+ virtual QString name() const override;
+ virtual bool initialize(const QVariantHash ¶ms) override;
+ virtual bool create(QMenu *parent) override;
+ virtual bool triggered(QAction *action) override;
+ virtual void updateState(QMenu *parent) override;
+
+ static void doReencryptDevice(const disk_encrypt::DeviceEncryptParam ¶m);
+
+protected:
+ static void encryptDevice(const disk_encrypt::DeviceEncryptParam ¶m);
+ static void decryptDevice(const disk_encrypt::DeviceEncryptParam ¶m);
+ static void changePassphrase(disk_encrypt::DeviceEncryptParam param);
+ static void unlockDevice(const QString &dev);
+
+ static void doEncryptDevice(const disk_encrypt::DeviceEncryptParam ¶m);
+ static void doDecryptDevice(const disk_encrypt::DeviceEncryptParam ¶m);
+ static void doChangePassphrase(const disk_encrypt::DeviceEncryptParam ¶m);
+
+ static QString generateTPMConfig();
+ static QString generateTPMToken(const QString &device, bool pin);
+ static QString getBase64Of(const QString &fileName);
+
+ static void onUnlocked(bool ok, dfmmount::OperationErrorInfo, QString);
+ static void onMounted(bool ok, dfmmount::OperationErrorInfo, QString);
+
+ static void unmountBefore(const std::function &after, const disk_encrypt::DeviceEncryptParam ¶m);
+ enum OpType { kUnmount,
+ kLock };
+ static void onUnmountError(OpType t, const QString &dev, const dfmmount::OperationErrorInfo &err);
+
+ static QString encryptPasswd(const QString &passwd);
+
+ void sortActions(QMenu *parent);
+ void updateActions();
+
+private:
+ QMap actions;
+ bool hasCryptHeader { false };
+ QVariantHash selectedItemInfo;
+ disk_encrypt::DeviceEncryptParam param;
+};
+
+}
+
+#endif // DISKENCRYPTMENUSCENE_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/plugin_diskencryptentry.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/plugin_diskencryptentry.cpp
new file mode 100644
index 0000000000..468ccabb7b
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/plugin_diskencryptentry.cpp
@@ -0,0 +1,100 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "plugin_diskencryptentry.h"
+#include "menu/diskencryptmenuscene.h"
+#include "events/eventshandler.h"
+
+#include
+
+#include
+#include
+#include
+
+using namespace dfmplugin_diskenc;
+
+bool hasComputerMenuRegisted()
+{
+ return dpfSlotChannel->push(kMenuPluginName, "slot_MenuScene_Contains", QString(kComputerMenuSceneName)).toBool();
+}
+
+void DiskEncryptEntry::initialize()
+{
+ auto i18n = new QTranslator(this);
+ i18n->load(QLocale(), "disk-encrypt", "_", "/usr/share/dde-file-manager/translations");
+ QCoreApplication::installTranslator(i18n);
+}
+
+bool DiskEncryptEntry::start()
+{
+ dpfSlotChannel->push(kMenuPluginName, "slot_MenuScene_RegisterScene",
+ DiskEncryptMenuCreator::name(), new DiskEncryptMenuCreator);
+
+ if (hasComputerMenuRegisted()) {
+ dpfSlotChannel->push("dfmplugin_menu", "slot_MenuScene_Bind",
+ DiskEncryptMenuCreator::name(), QString(kComputerMenuSceneName));
+ } else {
+ dpfSignalDispatcher->subscribe(kMenuPluginName, "signal_MenuScene_SceneAdded",
+ this, &DiskEncryptEntry::onComputerMenuSceneAdded);
+ }
+
+ EventsHandler::instance()->bindDaemonSignals();
+ EventsHandler::instance()->hookEvents();
+
+ QString decJob = EventsHandler::instance()->unfinishedDecryptJob();
+ if (!decJob.isEmpty() && !EventsHandler::instance()->isTaskWorking()) {
+ QTimer::singleShot(1000, this, [=] {
+ processUnfinshedDecrypt(decJob);
+ });
+ }
+
+ return true;
+}
+
+void DiskEncryptEntry::onComputerMenuSceneAdded(const QString &scene)
+{
+ if (scene == "ComputerMenu") {
+ dpfSlotChannel->push(kMenuPluginName, "slot_MenuScene_Bind",
+ DiskEncryptMenuCreator::name(), kComputerMenuSceneName);
+ dpfSignalDispatcher->unsubscribe("dfmplugin_menu", "signal_MenuScene_SceneAdded",
+ this, &DiskEncryptEntry::onComputerMenuSceneAdded);
+ }
+}
+
+void DiskEncryptEntry::processUnfinshedDecrypt(const QString &device)
+{
+ QString dev(device);
+ QString ignoreFile = "/tmp/dfm_ignore_decrypt_auto_reqeust_" + dev.replace("/", "_");
+ if (QFile(ignoreFile).exists())
+ return;
+
+ QMenu *menu = new QMenu();
+ DiskEncryptMenuScene *scene = new DiskEncryptMenuScene();
+
+ QUrl url;
+ url.setScheme("entry");
+ url.setPath(QString("%1.blockdev").arg(device.mid(5)));
+ QVariant urls = QVariant::fromValue>({ url });
+ QVariantHash params;
+ params.insert(dfmbase::MenuParamKey::kSelectFiles, urls);
+ scene->initialize(params);
+ scene->create(menu);
+ scene->updateState(menu);
+
+ auto actions = menu->actions();
+ auto ret = std::find_if(actions.cbegin(), actions.cend(), [](QAction *act) {
+ qWarning() << act->property(dfmbase::ActionPropertyKey::kActionID).toString();
+ return act->property(dfmbase::ActionPropertyKey::kActionID).toString() == "de_1_decrypt";
+ });
+ if (ret == actions.cend())
+ return;
+
+ scene->triggered(*ret);
+ delete scene;
+ delete menu;
+
+ QFile f(ignoreFile);
+ f.open(QIODevice::Truncate | QIODevice::WriteOnly);
+ f.close();
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/plugin_diskencryptentry.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/plugin_diskencryptentry.h
new file mode 100644
index 0000000000..1638f6c988
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/plugin_diskencryptentry.h
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef DISKENCRYPTENTRY_H
+#define DISKENCRYPTENTRY_H
+
+#include "dfmplugin_disk_encrypt_global.h"
+
+#include
+
+namespace dfmplugin_diskenc {
+
+class DFMPLUGIN_DISK_ENCRYPT_EXPORT DiskEncryptEntry : public dpf::Plugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.deepin.plugin.filemanager" FILE "diskencryptentry.json")
+
+ // Plugin interface
+public:
+ virtual void initialize() override;
+ virtual bool start() override;
+
+private:
+ void onComputerMenuSceneAdded(const QString &scene);
+ void processUnfinshedDecrypt(const QString &device);
+};
+}
+
+#endif // DISKENCRYPTENTRY_H
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/translate.sh b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/translate.sh
new file mode 100755
index 0000000000..4bcc9f418e
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/translate.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# SPDX-FileCopyrightText: 2022 - 2023 UnionTech Software Technology Co., Ltd.
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+lupdate ./ -ts -no-obsolete ../../../translations/disk-encrypt.ts
+lupdate ./ -ts -no-obsolete ../../../translations/disk-encrypt_zh_CN.ts
+lupdate ./ -ts -no-obsolete ../../../translations/disk-encrypt_zh_HK.ts
+lupdate ./ -ts -no-obsolete ../../../translations/disk-encrypt_zh_TW.ts
\ No newline at end of file
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/utils/encryptutils.cpp b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/utils/encryptutils.cpp
new file mode 100644
index 0000000000..1a34549e6b
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/utils/encryptutils.cpp
@@ -0,0 +1,501 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "encryptutils.h"
+#include "dfmplugin_disk_encrypt_global.h"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+Q_DECLARE_METATYPE(bool *)
+Q_DECLARE_METATYPE(QString *)
+
+using namespace dfmplugin_diskenc;
+
+bool config_utils::exportKeyEnabled()
+{
+ auto cfg = Dtk::Core::DConfig::create("org.deepin.dde.file-manager",
+ "org.deepin.dde.file-manager.diskencrypt");
+ cfg->deleteLater();
+ return cfg->value("allowExportEncKey", true).toBool();
+}
+
+QString config_utils::cipherType()
+{
+ auto cfg = Dtk::Core::DConfig::create("org.deepin.dde.file-manager",
+ "org.deepin.dde.file-manager.diskencrypt");
+ cfg->deleteLater();
+ auto cipher = cfg->value("encryptAlgorithm", "sm4").toString();
+ QStringList supportedCipher { "sm4", "aes" };
+ if (!supportedCipher.contains(cipher))
+ return "sm4";
+ return cipher;
+}
+
+bool fstab_utils::isFstabItem(const QString &mpt)
+{
+ if (mpt.isEmpty())
+ return false;
+
+ bool fstabed { false };
+ struct fstab *fs;
+ setfsent();
+ while ((fs = getfsent()) != nullptr) {
+ QString path = fs->fs_file;
+ if (mpt == path) {
+ fstabed = true;
+ break;
+ }
+ }
+ endfsent();
+ return fstabed;
+}
+
+int tpm_utils::checkTPM()
+{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_TPMIsAvailablePro").toInt();
+}
+
+int tpm_utils::getRandomByTPM(int size, QString *output)
+{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_GetRandomByTPMPro", size, output).toInt();
+}
+
+int tpm_utils::isSupportAlgoByTPM(const QString &algoName, bool *support)
+{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_IsTPMSupportAlgoPro", algoName, support).toInt();
+}
+
+int tpm_utils::encryptByTPM(const QVariantMap &map)
+{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_EncryptByTPMPro", map).toInt();
+}
+
+int tpm_utils::decryptByTPM(const QVariantMap &map, QString *psw)
+{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_DecryptByTPMPro", map, psw).toInt();
+}
+
+int tpm_utils::ownerAuthStatus()
+{
+ return dpfSlotChannel->push("dfmplugin_encrypt_manager", "slot_OwnerAuthStatus").toInt();
+}
+
+int device_utils::encKeyType(const QString &dev)
+{
+ QDBusInterface iface(kDaemonBusName,
+ kDaemonBusPath,
+ kDaemonBusIface,
+ QDBusConnection::systemBus());
+ if (iface.isValid()) {
+ QDBusReply reply = iface.call("QueryTPMToken", dev);
+ if (!reply.isValid()) return 0;
+ QString tokenJson = reply.value();
+ if (tokenJson.isEmpty()) return 0;
+
+ QJsonDocument doc = QJsonDocument::fromJson(tokenJson.toLocal8Bit());
+ QJsonObject obj = doc.object();
+ cacheToken(dev, obj.toVariantMap());
+ QString usePin = obj.value("pin").toString("");
+ if (usePin.isEmpty()) return 0;
+ if (usePin == "1") return 1;
+ if (usePin == "0") return 2;
+ }
+ return 0;
+}
+
+int tpm_passphrase_utils::genPassphraseFromTPM(const QString &dev, const QString &pin, QString *passphrase)
+{
+ Q_ASSERT(passphrase);
+
+ if ((tpm_utils::getRandomByTPM(kPasswordSize, passphrase) != 0)
+ || passphrase->isEmpty()) {
+ qCritical() << "TPM get random number failed!";
+ return kTPMNoRandomNumber;
+ }
+
+ const QString dirPath = kGlobalTPMConfigPath + dev;
+ QDir dir(dirPath);
+ if (!dir.exists())
+ dir.mkpath(dirPath);
+
+ QString sessionHashAlgo, sessionKeyAlgo, primaryHashAlgo, primaryKeyAlgo, minorHashAlgo, minorKeyAlgo;
+ if (!getAlgorithm(&sessionHashAlgo, &sessionKeyAlgo, &primaryHashAlgo, &primaryKeyAlgo, &minorHashAlgo, &minorKeyAlgo)) {
+ qCritical() << "TPM algo choice failed!";
+ return kTPMMissingAlog;
+ }
+
+ QVariantMap map {
+ { "PropertyKey_SessionHashAlgo", sessionHashAlgo },
+ { "PropertyKey_SessionKeyAlgo", sessionKeyAlgo },
+ { "PropertyKey_PrimaryHashAlgo", primaryHashAlgo },
+ { "PropertyKey_PrimaryKeyAlgo", primaryKeyAlgo },
+ { "PropertyKey_MinorHashAlgo", minorHashAlgo },
+ { "PropertyKey_MinorKeyAlgo", minorKeyAlgo },
+ { "PropertyKey_DirPath", dirPath },
+ { "PropertyKey_Plain", *passphrase },
+ };
+ if (pin.isEmpty()) {
+ map.insert("PropertyKey_EncryptType", kUseTpmAndPcr);
+ map.insert("PropertyKey_Pcr", "7");
+ map.insert("PropertyKey_PcrBank", primaryHashAlgo);
+ } else {
+ map.insert("PropertyKey_EncryptType", kUseTpmAndPrcAndPin);
+ map.insert("PropertyKey_Pcr", "7");
+ map.insert("PropertyKey_PcrBank", primaryHashAlgo);
+ map.insert("PropertyKey_PinCode", pin);
+ }
+
+ int err = tpm_utils::encryptByTPM(map);
+ if (err != 0) {
+ qCritical() << "save to TPM failed!!!";
+ return TPMError(err);
+ }
+
+ QSettings settings(dirPath + QDir::separator() + "algo.ini", QSettings::IniFormat);
+ settings.setValue(kConfigKeySessionHashAlgo, QVariant(sessionHashAlgo));
+ settings.setValue(kConfigKeyPriKeyAlgo, QVariant(sessionKeyAlgo));
+ settings.setValue(kConfigKeyPriHashAlgo, QVariant(primaryHashAlgo));
+ settings.setValue(kConfigKeyPriKeyAlgo, QVariant(primaryKeyAlgo));
+
+ return kTPMNoError;
+}
+
+QString tpm_passphrase_utils::getPassphraseFromTPM(const QString &dev, const QString &pin)
+{
+ const QString dirPath = kGlobalTPMConfigPath + dev;
+ QSettings tpmSets(dirPath + QDir::separator() + "algo.ini", QSettings::IniFormat);
+ const QString sessionHashAlgo = tpmSets.value(kConfigKeySessionHashAlgo).toString();
+ const QString sessionKeyAlgo = tpmSets.value(kConfigKeySessionKeyAlgo).toString();
+ const QString primaryHashAlgo = tpmSets.value(kConfigKeyPriHashAlgo).toString();
+ const QString primaryKeyAlgo = tpmSets.value(kConfigKeyPriKeyAlgo).toString();
+ QVariantMap map {
+ { "PropertyKey_EncryptType", (pin.isEmpty() ? kUseTpmAndPcr : kUseTpmAndPrcAndPin) },
+ { "PropertyKey_SessionHashAlgo", (sessionHashAlgo.isEmpty() ? "sha256" : sessionHashAlgo) }, // TODO:gongheng need help by liangbo
+ { "PropertyKey_SessionKeyAlgo", (sessionKeyAlgo.isEmpty() ? "aes" : sessionKeyAlgo) },
+ { "PropertyKey_PrimaryHashAlgo", primaryHashAlgo },
+ { "PropertyKey_PrimaryKeyAlgo", primaryKeyAlgo },
+ { "PropertyKey_DirPath", dirPath }
+ };
+
+ QString tokenDocPath = dirPath + QDir::separator() + "token.json";
+ QFile file(tokenDocPath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCritical() << "Failed to open token.json!";
+ return "";
+ }
+ QJsonDocument tokenDoc = QJsonDocument::fromJson(file.readAll());
+ file.close();
+
+ QJsonObject obj = tokenDoc.object();
+ if (!obj.contains("pcr") || !obj.contains("pcr-bank")) {
+ qCritical() << "Failed to get pcr or pcr-bank from token.json!";
+ return "";
+ }
+ const QString pcr = obj.value("pcr").toString();
+ const QString pcr_bank = obj.value("pcr-bank").toString();
+ if (!pin.isEmpty())
+ map.insert("PropertyKey_PinCode", pin);
+ map.insert("PropertyKey_Pcr", pcr);
+ map.insert("PropertyKey_PcrBank", pcr_bank);
+
+ QString passphrase;
+ int ok = tpm_utils::decryptByTPM(map, &passphrase);
+ if (ok != 0) {
+ qWarning() << "cannot acquire passphrase from TPM for device"
+ << dev;
+ }
+
+ return passphrase;
+}
+
+bool tpm_passphrase_utils::getAlgorithm(QString *sessionHashAlgo, QString *sessionKeyAlgo,
+ QString *primaryHashAlgo, QString *primaryKeyAlgo,
+ QString *minorHashAlgo, QString *minorKeyAlgo)
+{
+ bool re1 { false };
+ bool re2 { false };
+ bool re3 { false };
+ bool re4 { false };
+ bool re5 { false };
+ bool re6 { false };
+ tpm_utils::isSupportAlgoByTPM(kTPMSessionHashAlgo, &re1);
+ tpm_utils::isSupportAlgoByTPM(kTPMSessionKeyAlgo, &re2);
+ tpm_utils::isSupportAlgoByTPM(kTPMPrimaryHashAlgo, &re3);
+ tpm_utils::isSupportAlgoByTPM(kTPMPrimaryKeyAlgo, &re4);
+ tpm_utils::isSupportAlgoByTPM(kTPMMinorHashAlgo, &re5);
+ tpm_utils::isSupportAlgoByTPM(kTPMMinorKeyAlgo, &re6);
+
+ if (re1 && re2 && re3 && re4 && re5 && re6) {
+ (*sessionHashAlgo) = kTPMSessionHashAlgo;
+ (*sessionKeyAlgo) = kTPMSessionKeyAlgo;
+ (*primaryHashAlgo) = kTPMPrimaryHashAlgo;
+ (*primaryKeyAlgo) = kTPMPrimaryKeyAlgo;
+ (*minorHashAlgo) = kTPMMinorHashAlgo;
+ (*minorKeyAlgo) = kTPMMinorKeyAlgo;
+ return true;
+ }
+
+ re1 = false;
+ re2 = false;
+ re3 = false;
+ re4 = false;
+ re5 = false;
+ re6 = false;
+ tpm_utils::isSupportAlgoByTPM(kTCMSessionHashAlgo, &re1);
+ tpm_utils::isSupportAlgoByTPM(kTCMSessionKeyAlgo, &re2);
+ tpm_utils::isSupportAlgoByTPM(kTCMPrimaryHashAlgo, &re3);
+ tpm_utils::isSupportAlgoByTPM(kTCMPrimaryKeyAlgo, &re4);
+ tpm_utils::isSupportAlgoByTPM(kTCMMinorHashAlgo, &re5);
+ tpm_utils::isSupportAlgoByTPM(kTCMMinorKeyAlgo, &re6);
+
+ if (re1 && re2 && re3 && re4 && re5 && re6) {
+ (*sessionHashAlgo) = kTCMSessionHashAlgo;
+ (*sessionKeyAlgo) = kTCMSessionKeyAlgo;
+ (*primaryHashAlgo) = kTCMPrimaryHashAlgo;
+ (*primaryKeyAlgo) = kTCMPrimaryKeyAlgo;
+ (*minorHashAlgo) = kTCMMinorHashAlgo;
+ (*minorKeyAlgo) = kTCMMinorKeyAlgo;
+ return true;
+ }
+
+ return false;
+}
+
+QString recovery_key_utils::formatRecoveryKey(const QString &raw)
+{
+ static const int kSectionLen = 6;
+ QString formatted = raw;
+ formatted.remove("-");
+ int len = formatted.length();
+ if (len > 24)
+ formatted = formatted.mid(0, 24);
+
+ len = formatted.length();
+ int dashCount = len / kSectionLen;
+ if (len % kSectionLen == 0)
+ dashCount -= 1;
+ for (; dashCount > 0; dashCount--)
+ formatted.insert(dashCount * kSectionLen, '-');
+ return formatted;
+}
+
+BlockDev device_utils::createBlockDevice(const QString &devObjPath)
+{
+ using namespace dfmmount;
+ auto monitor = DDeviceManager::instance()->getRegisteredMonitor(DeviceType::kBlockDevice).objectCast();
+ Q_ASSERT(monitor);
+ return monitor->createDeviceById(devObjPath).objectCast();
+}
+
+int dialog_utils::showDialog(const QString &title, const QString &msg, DialogType type)
+{
+ QString icon;
+ switch (type) {
+ case kInfo:
+ icon = "dialog-information";
+ break;
+ case kWarning:
+ icon = "dialog-warning";
+ break;
+ case kError:
+ icon = "dialog-error";
+ break;
+ }
+ Dtk::Widget::DDialog d;
+ if (isWayland())
+ d.setWindowFlag(Qt::WindowStaysOnTopHint);
+ d.setTitle(title);
+ d.setMessage(msg);
+ d.setIcon(QIcon::fromTheme(icon));
+ d.addButton(qApp->translate("dfmplugin_diskenc::ChgPassphraseDialog", "Confirm"));
+ return d.exec();
+}
+
+void device_utils::cacheToken(const QString &device, const QVariantMap &token)
+{
+ if (token.isEmpty()) {
+ QDir tmp("/tmp");
+ tmp.rmpath(kGlobalTPMConfigPath + device);
+ return;
+ }
+
+ auto makeFile = [](const QString &fileName, const QByteArray &content) {
+ QFile f(fileName);
+ if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
+ qWarning() << "cannot cache token!" << fileName;
+ return false;
+ }
+
+ f.write(content);
+ f.flush();
+ f.close();
+ return true;
+ };
+
+ QString devTpmConfigPath = kGlobalTPMConfigPath + device;
+ QDir tpmPath(devTpmConfigPath);
+ if (!tpmPath.exists())
+ tpmPath.mkpath(devTpmConfigPath);
+
+ QJsonObject obj = QJsonObject::fromVariantMap(token);
+ QJsonDocument doc(obj);
+ QByteArray iv = obj.value("iv").toString().toLocal8Bit();
+ QByteArray keyPriv = obj.value("kek-priv").toString().toLocal8Bit();
+ QByteArray keyPub = obj.value("kek-pub").toString().toLocal8Bit();
+ QByteArray cipher = obj.value("enc").toString().toLocal8Bit();
+ iv = QByteArray::fromBase64(iv);
+ keyPriv = QByteArray::fromBase64(keyPriv);
+ keyPub = QByteArray::fromBase64(keyPub);
+ cipher = QByteArray::fromBase64(cipher);
+
+ bool ret = true;
+ ret &= makeFile(devTpmConfigPath + "/token.json", doc.toJson());
+ ret &= makeFile(devTpmConfigPath + "/iv.bin", iv);
+ ret &= makeFile(devTpmConfigPath + "/key.priv", keyPriv);
+ ret &= makeFile(devTpmConfigPath + "/key.pub", keyPub);
+ ret &= makeFile(devTpmConfigPath + "/cipher.out", cipher);
+
+ QSettings algo(devTpmConfigPath + "/algo.ini", QSettings::IniFormat);
+ algo.setValue("session_hash_algo", obj.value("session-hash-alg").toString());
+ algo.setValue("session_key_algo", obj.value("session-key-alg").toString());
+ algo.setValue("primary_hash_algo", obj.value("primary-hash-alg").toString());
+ algo.setValue("primary_key_algo", obj.value("primary-key-alg").toString());
+
+ if (!ret)
+ tpmPath.rmpath(devTpmConfigPath);
+}
+
+void dialog_utils::showTPMError(const QString &title, tpm_passphrase_utils::TPMError err)
+{
+ QString msg;
+ switch (err) {
+ case tpm_passphrase_utils::kTPMNoRandomNumber:
+ msg = QObject::tr("Cannot generate random number by TPM");
+ break;
+ case tpm_passphrase_utils::kTPMMissingAlog:
+ msg = QObject::tr("No available encrypt algorithm.");
+ break;
+ case tpm_passphrase_utils::kTPMEncryptFailed:
+ msg = QObject::tr("TPM encrypt failed.");
+ break;
+ case tpm_passphrase_utils::kTPMLocked:
+ msg = QObject::tr("TPM is locked.");
+ break;
+ default:
+ break;
+ }
+ if (!msg.isEmpty())
+ showDialog(title, msg, kError);
+}
+
+bool dialog_utils::isWayland()
+{
+ return QApplication::platformName() == "wayland";
+}
+
+bool config_utils::enableEncrypt()
+{
+ auto cfg = Dtk::Core::DConfig::create("org.deepin.dde.file-manager",
+ "org.deepin.dde.file-manager.diskencrypt");
+ cfg->deleteLater();
+ return cfg->value("enableEncrypt", true).toBool();
+}
+
+int dialog_utils::showConfirmEncryptionDialog(const QString &device, bool needReboot)
+{
+ Dtk::Widget::DDialog dlg(qApp->activeWindow());
+ if (isWayland())
+ dlg.setWindowFlag(Qt::WindowStaysOnTopHint);
+ dlg.setIcon(QIcon::fromTheme("drive-harddisk-root"));
+ dlg.setTitle(QObject::tr("Confirm encrypt %1?").arg(device));
+ QWidget *wid = new QWidget(&dlg);
+ QVBoxLayout *lay = new QVBoxLayout(wid);
+ QLabel *hint1 = new QLabel(QObject::tr("The current partition is about to be encrypted and cannot be canceled during "
+ "the encryption process, please confirm the encryption."),
+ wid);
+ hint1->setAlignment(Qt::AlignLeft);
+ hint1->setWordWrap(true);
+ lay->addWidget(hint1);
+
+ QLabel *hint2 = new QLabel(QObject::tr("* After encrypting the partition, "
+ "the system cannot be rolled back to a lower version, "
+ "please confirm the encryption"),
+ wid);
+ hint2->setAlignment(Qt::AlignLeft);
+ hint2->setWordWrap(true);
+ QPalette pal = hint2->palette();
+ pal.setColor(QPalette::WindowText, QColor("red"));
+ hint2->setPalette(pal);
+ lay->addWidget(hint2);
+ dlg.addContent(wid);
+ dlg.addButton(QObject::tr("Cancel"));
+ needReboot ? dlg.addButton(QObject::tr("Confirm and Reboot"), true, Dtk::Widget::DDialog::ButtonRecommend)
+ : dlg.addButton(QObject::tr("Confirm"), true, Dtk::Widget::DDialog::ButtonRecommend);
+ return dlg.exec();
+}
+
+int dialog_utils::showConfirmDecryptionDialog(const QString &device, bool needReboot)
+{
+ Dtk::Widget::DDialog dlg(qApp->activeWindow());
+ if (isWayland())
+ dlg.setWindowFlag(Qt::WindowStaysOnTopHint);
+ dlg.setIcon(QIcon::fromTheme("drive-harddisk-root"));
+ dlg.setTitle(QObject::tr("Decrypt %1?").arg(device));
+ dlg.setMessage(QObject::tr("Decryption can take a long time, "
+ "so make sure power is connected until the decryption is complete."));
+ dlg.addButton(QObject::tr("Cancel"));
+ QString confirmTxt = needReboot ? QObject::tr("Confirm and Reboot") : QObject::tr("Confirm");
+ dlg.addButton(confirmTxt, true, Dtk::Widget::DDialog::ButtonRecommend);
+ return dlg.exec();
+}
+
+QString tpm_passphrase_utils::getPassphraseFromTPM_NonBlock(const QString &dev, const QString &pin)
+{
+ QEventLoop loop;
+ QFutureWatcher watcher;
+ QObject::connect(&watcher, &QFutureWatcher::finished, [&] { loop.exit(); });
+ watcher.setFuture(QtConcurrent::run(tpm_passphrase_utils::getPassphraseFromTPM,
+ dev,
+ pin));
+
+ qApp->setOverrideCursor(Qt::WaitCursor);
+ loop.exec();
+ qApp->restoreOverrideCursor();
+ return watcher.result();
+}
+
+int tpm_passphrase_utils::genPassphraseFromTPM_NonBlock(const QString &dev, const QString &pin, QString *passphrase)
+{
+ QEventLoop loop;
+ QFutureWatcher watcher;
+ QObject::connect(&watcher, &QFutureWatcher::finished, [&] { loop.exit(); });
+ watcher.setFuture(QtConcurrent::run(tpm_passphrase_utils::genPassphraseFromTPM,
+ dev,
+ pin,
+ passphrase));
+
+ qApp->setOverrideCursor(Qt::WaitCursor);
+ loop.exec();
+ qApp->restoreOverrideCursor();
+ return watcher.result();
+}
diff --git a/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/utils/encryptutils.h b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/utils/encryptutils.h
new file mode 100644
index 0000000000..be676dada5
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-disk-encrypt-entry/utils/encryptutils.h
@@ -0,0 +1,83 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef ENCRYPTUTILS_H
+#define ENCRYPTUTILS_H
+
+#include
+#include
+
+namespace dfmmount {
+class DBlockDevice;
+}
+
+typedef QSharedPointer BlockDev;
+
+namespace dfmplugin_diskenc {
+
+namespace tpm_utils {
+int checkTPM();
+int getRandomByTPM(int size, QString *output);
+int isSupportAlgoByTPM(const QString &algoName, bool *support);
+int encryptByTPM(const QVariantMap &map);
+int decryptByTPM(const QVariantMap &map, QString *psw);
+int ownerAuthStatus();
+} // namespace tpm_utils
+
+namespace tpm_passphrase_utils {
+
+enum TPMError {
+ kTPMNoError,
+ kTPMEncryptFailed,
+ kTPMLocked,
+ kTPMNoRandomNumber,
+ kTPMMissingAlog,
+};
+
+bool getAlgorithm(QString *sessionHashAlgo, QString *sessionKeyAlgo,
+ QString *primaryHashAlgo, QString *primaryKeyAlgo,
+ QString *minorHashAlgo, QString *minorKeyAlgo);
+int genPassphraseFromTPM(const QString &dev, const QString &pin, QString *passphrase);
+QString getPassphraseFromTPM(const QString &dev, const QString &pin);
+
+int genPassphraseFromTPM_NonBlock(const QString &dev, const QString &pin, QString *passphrase);
+QString getPassphraseFromTPM_NonBlock(const QString &dev, const QString &pin);
+}
+
+namespace config_utils {
+bool exportKeyEnabled();
+QString cipherType();
+bool enableEncrypt();
+} // namespace config_utils
+
+namespace recovery_key_utils {
+QString formatRecoveryKey(const QString &raw);
+}
+
+namespace fstab_utils {
+bool isFstabItem(const QString &mpt);
+} // namespace fstab_utils
+
+namespace device_utils {
+int encKeyType(const QString &dev);
+void cacheToken(const QString &device, const QVariantMap &token);
+BlockDev createBlockDevice(const QString &devObjPath);
+} // namespace device_utils
+
+namespace dialog_utils {
+enum DialogType {
+ kInfo,
+ kWarning,
+ kError,
+};
+int showDialog(const QString &title, const QString &msg, DialogType type);
+int showConfirmEncryptionDialog(const QString &device, bool needReboot);
+int showConfirmDecryptionDialog(const QString &device, bool needReboot);
+void showTPMError(const QString &title, tpm_passphrase_utils::TPMError err);
+bool isWayland();
+}
+
+} // namespace dfmplugin_diskenc
+
+#endif // ENCRYPTUTILS_H
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/CMakeLists.txt b/src/plugins/filemanager/dfmplugin-encrypt-manager/CMakeLists.txt
new file mode 100644
index 0000000000..acead1ca02
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(dfmplugin-encrypt-manager)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+find_package(Qt5 COMPONENTS Core REQUIRED)
+
+file(GLOB_RECURSE SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/*.json)
+
+add_library(${PROJECT_NAME} SHARED
+ ${SRC})
+
+set_target_properties(${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${DFM_BUILD_PLUGIN_FILEMANAGER_DIR})
+
+target_link_libraries(${PROJECT_NAME} PUBLIC
+ Qt5::Core)
+
+install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${DFM_PLUGIN_FILEMANAGER_CORE_DIR})
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/encrypt_manager_global.h b/src/plugins/filemanager/dfmplugin-encrypt-manager/encrypt_manager_global.h
new file mode 100644
index 0000000000..0085b2393a
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/encrypt_manager_global.h
@@ -0,0 +1,74 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef ENCRYPT_MANAGER_GLOBAL_H
+#define ENCRYPT_MANAGER_GLOBAL_H
+
+#define DPENCRYPTMANAGER_NAMESPACE dfmplugin_encrypt_manager
+#define DPENCRYPTMANAGER_BEGIN_NAMESPACE namespace dfmplugin_encrypt_manager {
+#define DPENCRYPTMANAGER_END_NAME }
+#define DPENCRYPTMANAGER_USE_NAMESPACE using namespace dfmplugin_encrypt_manager;
+
+#include
+
+namespace dfmplugin_encrypt_manager {
+
+enum TPMType {
+ kUnknow = 0,
+ kTpmAndPcr,
+ kTpmAndPin,
+ kTpmAndPcrAndPin
+};
+
+struct EncryptParams
+{
+ TPMType type;
+ QString sessionHashAlgo;
+ QString sessionKeyAlgo;
+ QString primaryHashAlgo;
+ QString primaryKeyAlgo;
+ QString minorHashAlgo;
+ QString minorKeyAlgo;
+ QString dirPath;
+ QString plain;
+
+ QString pinCode;
+
+ QString pcr;
+ QString pcr_bank;
+};
+
+struct DecryptParams
+{
+ TPMType type;
+ QString sessionHashAlgo;
+ QString sessionKeyAlgo;
+ QString primaryHashAlgo;
+ QString primaryKeyAlgo;
+ QString dirPath;
+
+ QString pinCode;
+
+ QString pcr;
+ QString pcr_bank;
+};
+
+namespace PropertyKey {
+inline constexpr char kEncryptType[] { "PropertyKey_EncryptType" };
+inline constexpr char kSessionHashAlgo[] { "PropertyKey_SessionHashAlgo" };
+inline constexpr char kSessionKeyAlgo[] { "PropertyKey_SessionKeyAlgo" };
+inline constexpr char kPrimaryHashAlgo[] { "PropertyKey_PrimaryHashAlgo" };
+inline constexpr char kPrimaryKeyAlgo[] { "PropertyKey_PrimaryKeyAlgo" };
+inline constexpr char kMinorHashAlgo[] { "PropertyKey_MinorHashAlgo" };
+inline constexpr char kMinorKeyAlgo[] { "PropertyKey_MinorKeyAlgo" };
+inline constexpr char kDirPath[] { "PropertyKey_DirPath" };
+inline constexpr char kPlain[] { "PropertyKey_Plain" };
+inline constexpr char kPinCode[] { "PropertyKey_PinCode" };
+inline constexpr char kPcr[] { "PropertyKey_Pcr" };
+inline constexpr char kPcrBank[] { "PropertyKey_PcrBank" };
+}
+
+}
+
+#endif // ENCRYPT_MANAGER_GLOBAL_H
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.cpp b/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.cpp
new file mode 100644
index 0000000000..b361d891ec
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.cpp
@@ -0,0 +1,19 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "encryptmanager.h"
+#include "events/eventreceiver.h"
+
+DPENCRYPTMANAGER_USE_NAMESPACE
+
+
+void EncryptManager::initialize()
+{
+ EventReceiver::instance();
+}
+
+bool EncryptManager::start()
+{
+ return true;
+}
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.h b/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.h
new file mode 100644
index 0000000000..4a2c99b79f
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.h
@@ -0,0 +1,40 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef ENCRYPTMANAGER_H
+#define ENCRYPTMANAGER_H
+
+#include "encrypt_manager_global.h"
+
+#include
+
+namespace dfmplugin_encrypt_manager {
+
+class EncryptManager : public dpf::Plugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.deepin.plugin.filemanager" FILE "encryptmanager.json")
+
+ DPF_EVENT_NAMESPACE(DPENCRYPTMANAGER_NAMESPACE)
+ // slot events
+ DPF_EVENT_REG_SLOT(slot_TPMIsAvailable)
+ DPF_EVENT_REG_SLOT(slot_GetRandomByTPM)
+ DPF_EVENT_REG_SLOT(slot_IsTPMSupportAlgo)
+ DPF_EVENT_REG_SLOT(slot_EncryptByTPM)
+ DPF_EVENT_REG_SLOT(slot_DecryptByTPM)
+ DPF_EVENT_REG_SLOT(slot_TPMIsAvailablePro)
+ DPF_EVENT_REG_SLOT(slot_GetRandomByTPMPro)
+ DPF_EVENT_REG_SLOT(slot_IsTPMSupportAlgoPro)
+ DPF_EVENT_REG_SLOT(slot_EncryptByTPMPro)
+ DPF_EVENT_REG_SLOT(slot_DecryptByTPMPro)
+ DPF_EVENT_REG_SLOT(slot_OwnerAuthStatus)
+
+public:
+ void initialize() override;
+ bool start() override;
+};
+
+}
+
+#endif // ENCRYPTMANAGER_H
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.json b/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.json
new file mode 100644
index 0000000000..301fdd0bfa
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/encryptmanager.json
@@ -0,0 +1,14 @@
+{
+ "Name" : "dfmplugin-encrypt-manager",
+ "Version" : "1.0.0",
+ "CompatVersion" : "1.0.0",
+ "Vendor" : "The Uniontech Software Technology Co., Ltd.",
+ "Copyright" : "Copyright (C) 2021 Uniontech Software Technology Co., Ltd.",
+ "License" : [
+ ],
+ "Category" : "",
+ "Description" : "The encrypt manager plugin for the filemanager.",
+ "UrlLink" : "https://www.uniontech.com",
+ "Depends" : [
+ ]
+}
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/events/eventreceiver.cpp b/src/plugins/filemanager/dfmplugin-encrypt-manager/events/eventreceiver.cpp
new file mode 100644
index 0000000000..d4eb18a62d
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/events/eventreceiver.cpp
@@ -0,0 +1,235 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "eventreceiver.h"
+#include "tpm/tpmwork.h"
+
+#include
+
+Q_DECLARE_METATYPE(QString *)
+Q_DECLARE_METATYPE(bool *)
+
+DPENCRYPTMANAGER_USE_NAMESPACE
+
+EventReceiver *EventReceiver::instance()
+{
+ static EventReceiver ins;
+ return &ins;
+}
+
+bool EventReceiver::tpmIsAvailable()
+{
+ TPMWork tpm;
+ return tpm.checkTPMAvailable();
+}
+
+bool EventReceiver::getRandomByTpm(int size, QString *output)
+{
+ TPMWork tpm;
+ if (!tpm.getRandom(size, output))
+ return false;
+
+ // Determine whether the password is a hexadecimal character
+ QString out = *output;
+ int count = out.size();
+ if (count != size) {
+ qCritical() << "Vault: random password create error! The error password is %1" << out;
+ return false;
+ }
+ for (int i = 0; i < count; ++i) {
+ if (!((out[i] >= '0' && out[i] <= '9') || (out[i] >= 'a' && out[i] <= 'f'))) {
+ qCritical() << "Vault: random password create error! The error password is %1" << out;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool EventReceiver::isTpmSupportAlgo(const QString &algoName, bool *support)
+{
+ if (algoName.isEmpty())
+ return false;
+
+ TPMWork tpm;
+ return tpm.isSupportAlgo(algoName, support);
+}
+
+bool EventReceiver::encrypyByTpm(const QString &hashAlgo, const QString &keyAlgo, const QString &keyPin, const QString &password, const QString &dirPath)
+{
+ TPMWork tpm;
+ return tpm.encrypt(hashAlgo, keyAlgo, keyPin, password, dirPath);
+}
+
+bool EventReceiver::decryptByTpm(const QString &keyPin, const QString &dirPath, QString *pwd)
+{
+ TPMWork tpm;
+ return tpm.decrypt(keyPin, dirPath, pwd);
+}
+
+int EventReceiver::tpmIsAvailableProcess()
+{
+ TPMWork tpm;
+ return tpm.checkTPMAvailbableByTools();
+}
+
+int EventReceiver::getRandomByTpmProcess(int size, QString *output)
+{
+ TPMWork tpm;
+ return tpm.getRandomByTools(size, output);
+}
+
+int EventReceiver::isTpmSupportAlgoProcess(const QString &algoName, bool *support)
+{
+ TPMWork tpm;
+ return tpm.isSupportAlgoByTools(algoName, support);
+}
+
+int EventReceiver::encryptByTpmProcess(const QVariantMap &encryptParams)
+{
+ if (!encryptParams.contains(PropertyKey::kEncryptType))
+ return -1;
+
+ int type = encryptParams.value(PropertyKey::kEncryptType).toInt();
+ if (type != 1 && type != 2 && type != 3)
+ return -1;
+
+ if (!encryptParams.contains(PropertyKey::kSessionHashAlgo)
+ || !encryptParams.contains(PropertyKey::kSessionKeyAlgo)
+ || !encryptParams.contains(PropertyKey::kPrimaryHashAlgo)
+ || !encryptParams.contains(PropertyKey::kPrimaryKeyAlgo)
+ || !encryptParams.contains(PropertyKey::kMinorHashAlgo)
+ || !encryptParams.contains(PropertyKey::kMinorKeyAlgo)
+ || !encryptParams.contains(PropertyKey::kDirPath)
+ || !encryptParams.contains(PropertyKey::kPlain)) {
+ return -1;
+ }
+
+ if (type == 1) {
+ if (!encryptParams.contains(PropertyKey::kPcr)
+ || !encryptParams.contains(PropertyKey::kPcrBank)) {
+ return -1;
+ }
+ } else if (type == 2) {
+ if (!encryptParams.contains(PropertyKey::kPinCode)) {
+ return -1;
+ }
+ } else if (type == 3) {
+ if (!encryptParams.contains(PropertyKey::kPcr)
+ || !encryptParams.contains(PropertyKey::kPcrBank)
+ || !encryptParams.contains(PropertyKey::kPinCode)) {
+ return -1;
+ }
+ }
+
+ EncryptParams params;
+ params.sessionHashAlgo = encryptParams.value(PropertyKey::kSessionHashAlgo).toString();
+ params.sessionKeyAlgo = encryptParams.value(PropertyKey::kSessionKeyAlgo).toString();
+ params.primaryHashAlgo = encryptParams.value(PropertyKey::kPrimaryHashAlgo).toString();
+ params.primaryKeyAlgo = encryptParams.value(PropertyKey::kPrimaryKeyAlgo).toString();
+ params.minorHashAlgo = encryptParams.value(PropertyKey::kMinorHashAlgo).toString();
+ params.minorKeyAlgo = encryptParams.value(PropertyKey::kMinorKeyAlgo).toString();
+ params.dirPath = encryptParams.value(PropertyKey::kDirPath).toString();
+ params.plain = encryptParams.value(PropertyKey::kPlain).toString();
+ if (type == 1) {
+ params.type = kTpmAndPcr;
+ params.pcr = encryptParams.value(PropertyKey::kPcr).toString();
+ params.pcr_bank = encryptParams.value(PropertyKey::kPcrBank).toString();
+ } else if (type == 2) {
+ params.type = kTpmAndPin;
+ params.pinCode = encryptParams.value(PropertyKey::kPinCode).toString();
+ } else if (type == 3) {
+ params.type = kTpmAndPcrAndPin;
+ params.pcr = encryptParams.value(PropertyKey::kPcr).toString();
+ params.pcr_bank = encryptParams.value(PropertyKey::kPcrBank).toString();
+ params.pinCode = encryptParams.value(PropertyKey::kPinCode).toString();
+ }
+ TPMWork tpm;
+ return tpm.encryptByTools(params);
+}
+
+int EventReceiver::decryptByTpmProcess(const QVariantMap &decryptParams, QString *pwd)
+{
+ if (!decryptParams.contains(PropertyKey::kEncryptType))
+ return -1;
+
+ int type = decryptParams.value(PropertyKey::kEncryptType).toInt();
+ if (type != 1 && type != 2 && type != 3)
+ return -1;
+
+ if (!decryptParams.contains(PropertyKey::kSessionHashAlgo)
+ || !decryptParams.contains(PropertyKey::kSessionKeyAlgo)
+ || !decryptParams.contains(PropertyKey::kPrimaryHashAlgo)
+ || !decryptParams.contains(PropertyKey::kPrimaryKeyAlgo)
+ || !decryptParams.contains(PropertyKey::kDirPath)) {
+ return false;
+ }
+
+ if (type == 1) {
+ if (!decryptParams.contains(PropertyKey::kPcr)
+ || !decryptParams.contains(PropertyKey::kPcrBank)) {
+ return false;
+ }
+ } else if (type == 2) {
+ if (!decryptParams.contains(PropertyKey::kPinCode)) {
+ return false;
+ }
+ } else if (type == 3) {
+ if (!decryptParams.contains(PropertyKey::kPcr)
+ || !decryptParams.contains(PropertyKey::kPcrBank)
+ || !decryptParams.contains(PropertyKey::kPinCode)) {
+ return false;
+ }
+ }
+
+ DecryptParams params;
+ params.sessionHashAlgo = decryptParams.value(PropertyKey::kSessionHashAlgo).toString();
+ params.sessionKeyAlgo = decryptParams.value(PropertyKey::kSessionKeyAlgo).toString();
+ params.primaryHashAlgo = decryptParams.value(PropertyKey::kPrimaryHashAlgo).toString();
+ params.primaryKeyAlgo = decryptParams.value(PropertyKey::kPrimaryKeyAlgo).toString();
+ params.dirPath = decryptParams.value(PropertyKey::kDirPath).toString();
+ if (type == 1) {
+ params.type = kTpmAndPcr;
+ params.pcr = decryptParams.value(PropertyKey::kPcr).toString();
+ params.pcr_bank = decryptParams.value(PropertyKey::kPcrBank).toString();
+ } else if (type == 2) {
+ params.type = kTpmAndPin;
+ params.pinCode = decryptParams.value(PropertyKey::kPinCode).toString();
+ } else if (type == 3) {
+ params.type = kTpmAndPcrAndPin;
+ params.pcr = decryptParams.value(PropertyKey::kPcr).toString();
+ params.pcr_bank = decryptParams.value(PropertyKey::kPcrBank).toString();
+ params.pinCode = decryptParams.value(PropertyKey::kPinCode).toString();
+ }
+
+ TPMWork tpm;
+ return tpm.decryptByTools(params, pwd);
+}
+
+int EventReceiver::ownerAuthStatus()
+{
+ return TPMWork().ownerAuthStatus();
+}
+
+EventReceiver::EventReceiver(QObject *parent)
+ : QObject(parent)
+{
+ initConnection();
+}
+
+void EventReceiver::initConnection()
+{
+ // slot event
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_TPMIsAvailable", this, &EventReceiver::tpmIsAvailable);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_GetRandomByTPM", this, &EventReceiver::getRandomByTpm);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_IsTPMSupportAlgo", this, &EventReceiver::isTpmSupportAlgo);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_EncryptByTPM", this, &EventReceiver::encrypyByTpm);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_DecryptByTPM", this, &EventReceiver::decryptByTpm);
+
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_TPMIsAvailablePro", this, &EventReceiver::tpmIsAvailableProcess);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_GetRandomByTPMPro", this, &EventReceiver::getRandomByTpmProcess);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_IsTPMSupportAlgoPro", this, &EventReceiver::isTpmSupportAlgoProcess);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_EncryptByTPMPro", this, &EventReceiver::encryptByTpmProcess);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_DecryptByTPMPro", this, &EventReceiver::decryptByTpmProcess);
+ dpfSlotChannel->connect("dfmplugin_encrypt_manager", "slot_OwnerAuthStatus", this, &EventReceiver::ownerAuthStatus);
+}
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/events/eventreceiver.h b/src/plugins/filemanager/dfmplugin-encrypt-manager/events/eventreceiver.h
new file mode 100644
index 0000000000..325fa5e3b0
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/events/eventreceiver.h
@@ -0,0 +1,42 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef EVENTRECEIVER_H
+#define EVENTRECEIVER_H
+
+#include "encrypt_manager_global.h"
+
+#include
+
+namespace dfmplugin_encrypt_manager {
+
+class EventReceiver : public QObject
+{
+ Q_OBJECT
+public:
+ static EventReceiver *instance();
+
+public Q_SLOTS:
+ bool tpmIsAvailable();
+ bool getRandomByTpm(int size, QString *output);
+ bool isTpmSupportAlgo(const QString &algoName, bool *support);
+ bool encrypyByTpm(const QString &hashAlgo, const QString &keyAlgo,
+ const QString &keyPin, const QString &password,
+ const QString &dirPath);
+ bool decryptByTpm(const QString &keyPin, const QString &dirPath, QString *pwd);
+
+ int tpmIsAvailableProcess();
+ int getRandomByTpmProcess(int size, QString *output);
+ int isTpmSupportAlgoProcess(const QString &algoName, bool *support);
+ int encryptByTpmProcess(const QVariantMap &encryptParams);
+ int decryptByTpmProcess(const QVariantMap &decryptParams, QString *pwd);
+ int ownerAuthStatus();
+
+private:
+ explicit EventReceiver(QObject *parent = nullptr);
+ void initConnection();
+};
+}
+
+#endif // EVENTRECEIVER_H
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/tpm/tpmwork.cpp b/src/plugins/filemanager/dfmplugin-encrypt-manager/tpm/tpmwork.cpp
new file mode 100644
index 0000000000..65c23a21da
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/tpm/tpmwork.cpp
@@ -0,0 +1,394 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "tpmwork.h"
+
+#include
+#include
+#include
+#include
+
+typedef enum {
+ kCTpmAndPcr,
+ kCTpmAndPin,
+ kCTpmAndPcrAndPin
+} TpmProType;
+
+typedef struct
+{
+ TpmProType type;
+ char *sessionHashAlgo;
+ char *sessionKeyAlgo;
+ char *primaryHashAlgo;
+ char *primaryKeyAlgo;
+ char *minorHashAlgo;
+ char *minorKeyAlgo;
+ char *dirPath;
+ char *plain;
+
+ char *pinCode;
+
+ char *pcr;
+ char *pcr_bank;
+} Utpm2EncryptParamsByTools;
+
+typedef struct
+{
+ TpmProType type;
+ char *sessionHashAlgo;
+ char *sessionKeyAlgo;
+ char *primaryHashAlgo;
+ char *primaryKeyAlgo;
+ char *dirPath;
+
+ char *pinCode;
+
+ char *pcr;
+ char *pcr_bank;
+} Utpm2DecryptParamsByTools;
+
+inline constexpr int kTpmOutTextMaxSize { 3000 };
+inline constexpr char kTpmLibName[] { "libutpm2.so" };
+inline constexpr char kTpmEncryptFileName[] { "tpm_encrypt.txt" };
+
+DPENCRYPTMANAGER_USE_NAMESPACE
+
+TPMWork::TPMWork(QObject *parent)
+ : QObject(parent), tpmLib(new QLibrary(kTpmLibName))
+{
+ if (!tpmLib->load())
+ qWarning() << "Vault: load utpm2 failed, the error is " << tpmLib->errorString();
+}
+
+TPMWork::~TPMWork()
+{
+ if (tpmLib) {
+ tpmLib->unload();
+ delete tpmLib;
+ tpmLib = nullptr;
+ }
+}
+
+bool TPMWork::checkTPMAvailable()
+{
+ if (!tpmLib->isLoaded())
+ return false;
+
+ QString output;
+ return getRandom(2, &output);
+}
+
+bool TPMWork::getRandom(int size, QString *output)
+{
+ if (!tpmLib->isLoaded())
+ return false;
+
+ if (size % 2 != 0 || size < 2 || size > 64) {
+ qCritical() << "Vault: random size must be even and greater than or equal to 2 and less than or equal to 64!";
+ return false;
+ }
+
+ typedef bool (*p_get_random)(uint16_t * size, uint8_t ranbytes[]);
+ p_get_random utpm2_get_random = (p_get_random)tpmLib->resolve("utpm2_get_random");
+ if (utpm2_get_random) {
+ uint16_t len = size / 2;
+ uint8_t *random = (uint8_t *)malloc(sizeof(uint8_t) * len);
+ memset(random, 0, sizeof(uint8_t) * len);
+ if (utpm2_get_random(&len, random)) {
+ char *out = (char *)malloc(sizeof(uint8_t) * size + 1);
+ memset(out, 0, sizeof(uint8_t) * size + 1);
+ for (size_t i = 0; i < len; ++i) {
+ sprintf(out + (i * 2), "%02x", random[i]);
+ }
+ *output = QString(out);
+ free(random);
+ free(out);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TPMWork::isSupportAlgo(const QString &algoName, bool *support)
+{
+ if (!tpmLib->isLoaded())
+ return false;
+
+ typedef bool (*p_check_algo)(const char *alg);
+ p_check_algo utpm2_check_algo = (p_check_algo)tpmLib->resolve("utpm2_check_alg");
+ if (utpm2_check_algo) {
+ QByteArray arAlgoName = algoName.toUtf8();
+ if (utpm2_check_algo(arAlgoName.data())) {
+ *support = true;
+ } else {
+ *support = false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool TPMWork::initTpm2(const QString &hashAlgo, const QString &keyAlgo, const QString &keyPin, const QString &dirPath)
+{
+ if (!tpmLib->isLoaded())
+ return false;
+
+ typedef bool (*p_init)(char *algdetail, char *galg, const char *auth, const char *dir);
+ p_init utpm2_init = (p_init)tpmLib->resolve("utpm2_init");
+ if (utpm2_init) {
+ QByteArray arKeyAlgo = keyAlgo.toUtf8();
+ QByteArray arHashAlgo = hashAlgo.toUtf8();
+ QByteArray arKeyPin = keyPin.toUtf8();
+ QByteArray arDir = dirPath.toUtf8();
+ if (utpm2_init(arKeyAlgo.data(), arHashAlgo.data(), arKeyPin.data(), arDir.data())) {
+ return true;
+ } else {
+ qCritical() << "Vault: utpm2_init return false!";
+ }
+ } else {
+ qCritical() << "Vault: resolve utpm2_init failed!";
+ }
+ return false;
+}
+
+bool TPMWork::encrypt(const QString &hashAlgo, const QString &keyAlgo, const QString &keyPin, const QString &password, const QString &dirPath)
+{
+ if (!initTpm2(hashAlgo, keyAlgo, keyPin, dirPath)) {
+ return false;
+ }
+
+ typedef int (*p_encrypt_decrypt)(const char *dir, bool isdecrypt, const char *auth, uint8_t inbytes[], uint8_t outbytes[], uint16_t *size);
+ p_encrypt_decrypt utpm2_encrypt_decrypt = (p_encrypt_decrypt)tpmLib->resolve("utpm2_encrypt_decrypt");
+ if (utpm2_encrypt_decrypt) {
+ QByteArray arDir = dirPath.toUtf8();
+ QByteArray arKeyPin = keyPin.toUtf8();
+ QByteArray arrPassword = password.toUtf8();
+ uint16_t len = static_cast(arrPassword.size());
+ uint8_t *inbuffer = reinterpret_cast(arrPassword.data());
+ uint8_t out_text[kTpmOutTextMaxSize] = { 0 };
+ if (utpm2_encrypt_decrypt(arDir.data(), false, arKeyPin.data(), inbuffer, out_text, &len)) {
+ QFile file(dirPath + QDir::separator() + kTpmEncryptFileName);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ file.write(reinterpret_cast(out_text), len);
+ file.close();
+ return true;
+ } else {
+ qCritical() << "Vault: open encrypt file failed!";
+ }
+ } else {
+ qCritical() << "Vault: utpm2_encry_decrypt return false!";
+ }
+ } else {
+ qCritical() << "Vault: resolve utpm2_encry_decrypt failed!";
+ }
+ return false;
+}
+
+bool TPMWork::decrypt(const QString &keyPin, const QString &dirPath, QString *psw)
+{
+ if (!tpmLib->isLoaded())
+ return false;
+
+ typedef int (*p_encrypt_decrypt)(const char *dir, bool isdecrypt, const char *auth, uint8_t inbytes[], uint8_t outbytes[], uint16_t *size);
+ p_encrypt_decrypt utpm2_encrypt_decrypt = (p_encrypt_decrypt)tpmLib->resolve("utpm2_encrypt_decrypt");
+ if (utpm2_encrypt_decrypt) {
+ QByteArray arDir = QString(dirPath).toUtf8();
+ QByteArray arKeyPin = keyPin.toUtf8();
+ QFile file(dirPath + QDir::separator() + kTpmEncryptFileName);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QByteArray ciphertext = file.readAll();
+ file.close();
+ uint16_t len = static_cast(ciphertext.size());
+ uint8_t out_text[kTpmOutTextMaxSize] = { 0 };
+ uint8_t *inbuffer = reinterpret_cast(ciphertext.data());
+ if (utpm2_encrypt_decrypt(arDir.data(), true, arKeyPin.data(), inbuffer, out_text, &len)) {
+ *psw = QString::fromUtf8(reinterpret_cast(out_text), len);
+ return true;
+ } else {
+ qCritical() << "Vault: utpm2_encry_decrypt return failed!";
+ }
+ } else {
+ qCritical() << "Vault: open encrypt file failed!";
+ }
+ } else {
+ qCritical() << "Vault: resolve utpm2_encry_decrypt failed!";
+ }
+ return false;
+}
+
+int TPMWork::checkTPMAvailbableByTools()
+{
+ if (!tpmLib->isLoaded())
+ return -1;
+
+ typedef int (*p_utpm2_check_tpm_by_tools)(void);
+ p_utpm2_check_tpm_by_tools utpm2_check_tpm_by_tools = (p_utpm2_check_tpm_by_tools)tpmLib->resolve("utpm2_check_tpm_by_tools");
+ if (!utpm2_check_tpm_by_tools) {
+ qCritical() << "resolve utpm2_check_tpm_by_tools failed!";
+ return -1;
+ }
+
+ return utpm2_check_tpm_by_tools();
+}
+
+int TPMWork::getRandomByTools(int size, QString *output)
+{
+ if (!tpmLib->isLoaded())
+ return -1;
+
+ typedef int (*p_utpm2_get_random_by_tools)(int size, char *buf);
+ p_utpm2_get_random_by_tools utpm2_get_random_by_tools = (p_utpm2_get_random_by_tools)tpmLib->resolve("utpm2_get_random_by_tools");
+ if (!utpm2_get_random_by_tools) {
+ qCritical() << "resolve utpm2_get_random_by_tools failed!";
+ return -1;
+ }
+
+ char buf[129] = { 0 };
+ int re = utpm2_get_random_by_tools(size, buf);
+ *output = QString::fromLatin1(buf);
+ return re;
+}
+
+int TPMWork::isSupportAlgoByTools(const QString &algoName, bool *support)
+{
+ if (!tpmLib->isLoaded())
+ return -1;
+
+ typedef int (*p_utpm2_check_alg_by_tools)(const char *algo_name, bool *support);
+ p_utpm2_check_alg_by_tools utpm2_check_alg_by_tools = (p_utpm2_check_alg_by_tools)tpmLib->resolve("utpm2_check_alg_by_tools");
+ if (!utpm2_check_alg_by_tools) {
+ qCritical() << "resolve utpm2_check_alg_by_tools failed!";
+ return -1;
+ }
+
+ QByteArray algo = algoName.toUtf8();
+ int re = utpm2_check_alg_by_tools(algo.data(), support);
+ return re;
+}
+
+int TPMWork::encryptByTools(const EncryptParams ¶ms)
+{
+ if (!tpmLib->isLoaded())
+ return -1;
+
+ typedef int (*utpm2_encrypt_by_tools)(const Utpm2EncryptParamsByTools *par);
+ utpm2_encrypt_by_tools func = (utpm2_encrypt_by_tools)tpmLib->resolve("utpm2_encrypt_by_tools");
+ if (!func) {
+ qCritical() << "resolve utpm2_encrypt_by_tools failed!";
+ return -1;
+ }
+
+ Utpm2EncryptParamsByTools pa;
+ if (params.type == kTpmAndPcr) {
+ pa.type = kCTpmAndPcr;
+ } else if (params.type == kTpmAndPin) {
+ pa.type = kCTpmAndPin;
+ } else if (params.type == kTpmAndPcrAndPin) {
+ pa.type = kCTpmAndPcrAndPin;
+ } else {
+ return -1;
+ }
+ QByteArray arrSessionHashAlgo = params.sessionHashAlgo.toUtf8();
+ pa.sessionHashAlgo = arrSessionHashAlgo.data();
+ QByteArray arrSessionKeyAlgo = params.sessionKeyAlgo.toUtf8();
+ pa.sessionKeyAlgo = arrSessionKeyAlgo.data();
+ QByteArray arrPriHashAlgo = params.primaryHashAlgo.toUtf8();
+ pa.primaryHashAlgo = arrPriHashAlgo.data();
+ QByteArray arrPriKeyAlgo = params.primaryKeyAlgo.toUtf8();
+ pa.primaryKeyAlgo = arrPriKeyAlgo.data();
+ QByteArray arrMinHashAlgo = params.minorHashAlgo.toUtf8();
+ pa.minorHashAlgo = arrMinHashAlgo.data();
+ QByteArray arrMinKeyAlgo = params.minorKeyAlgo.toUtf8();
+ pa.minorKeyAlgo = arrMinKeyAlgo.data();
+
+ QByteArray arrDirPath = params.dirPath.toUtf8();
+ pa.dirPath = arrDirPath.data();
+ QByteArray arrPlain = params.plain.toUtf8();
+ pa.plain = arrPlain.data();
+
+ QByteArray arrPinCode = params.pinCode.toUtf8();
+ pa.pinCode = arrPinCode.data();
+
+ QByteArray arrPcr = params.pcr.toUtf8();
+ pa.pcr = arrPcr.data();
+ QByteArray arrPcrBank = params.pcr_bank.toUtf8();
+ pa.pcr_bank = arrPcrBank.data();
+
+ int re = func(&pa);
+ if (re != 0) {
+ qCritical() << "utpm2_encrypt_by_tools return false!";
+ }
+
+ return re;
+}
+
+int TPMWork::decryptByTools(const DecryptParams ¶ms, QString *pwd)
+{
+ if (!tpmLib->isLoaded())
+ return -1;
+
+ typedef int (*utpm2_decrypt_by_tools)(const Utpm2DecryptParamsByTools *par, char *pwd, int *len);
+ utpm2_decrypt_by_tools fun = (utpm2_decrypt_by_tools)tpmLib->resolve("utpm2_decrypt_by_tools");
+ if (!fun) {
+ qCritical() << "resolve utpm2_encry_decrypt failed!";
+ return -1;
+ }
+
+ Utpm2DecryptParamsByTools pa;
+ if (params.type == kTpmAndPcr) {
+ pa.type = kCTpmAndPcr;
+ } else if (params.type == kTpmAndPin) {
+ pa.type = kCTpmAndPin;
+ } else if (params.type == kTpmAndPcrAndPin) {
+ pa.type = kCTpmAndPcrAndPin;
+ } else {
+ return -1;
+ }
+ QByteArray arrSessionHashAlgo = params.sessionHashAlgo.toUtf8();
+ pa.sessionHashAlgo = arrSessionHashAlgo.data();
+ QByteArray arrSessionKeyAlgo = params.sessionKeyAlgo.toUtf8();
+ pa.sessionKeyAlgo = arrSessionKeyAlgo.data();
+ QByteArray arrPriHashAlgo = params.primaryHashAlgo.toUtf8();
+ pa.primaryHashAlgo = arrPriHashAlgo.data();
+ QByteArray arrPriKeyAlgo = params.primaryKeyAlgo.toUtf8();
+ pa.primaryKeyAlgo = arrPriKeyAlgo.data();
+ QByteArray arrDirPath = params.dirPath.toUtf8();
+ pa.dirPath = arrDirPath.data();
+
+ QByteArray arrPinCode = params.pinCode.toUtf8();
+ pa.pinCode = arrPinCode.data();
+
+ QByteArray arrPcr = params.pcr.toUtf8();
+ pa.pcr = arrPcr.data();
+ QByteArray arrPcrBank = params.pcr_bank.toUtf8();
+ pa.pcr_bank = arrPcrBank.data();
+
+ char password[128] = { 0 };
+ int length = sizeof(password) - 1;
+ int re = fun(&pa, password, &length);
+ if (re != 0) {
+ qCritical() << "utpm2_encry_decrypt return failed!";
+ }
+ (*pwd) = QString::fromLatin1(password);
+
+ return re;
+}
+
+int TPMWork::ownerAuthStatus()
+{
+ typedef int (*utpm2_getcap_varprop_by_tools)(const char *prop_name, char *buf, size_t size);
+ utpm2_getcap_varprop_by_tools fun = (utpm2_getcap_varprop_by_tools)tpmLib->resolve("utpm2_getcap_varprop_by_tools");
+ if (!fun) {
+ qCritical() << "resolve utpm2_encry_decrypt failed!";
+ return -1;
+ }
+ char status[100];
+ int ret = fun("TPM2_PT_PERMANENT.ownerAuthSet", status, sizeof(status));
+ if (ret != 0) {
+ qCritical() << "cannot query ownerAuthSet";
+ return -2;
+ }
+ return QString(status).toInt();
+}
diff --git a/src/plugins/filemanager/dfmplugin-encrypt-manager/tpm/tpmwork.h b/src/plugins/filemanager/dfmplugin-encrypt-manager/tpm/tpmwork.h
new file mode 100644
index 0000000000..1614ebc362
--- /dev/null
+++ b/src/plugins/filemanager/dfmplugin-encrypt-manager/tpm/tpmwork.h
@@ -0,0 +1,48 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef TPMWORK_H
+#define TPMWORK_H
+
+#include "encrypt_manager_global.h"
+
+#include
+
+QT_BEGIN_NAMESPACE
+class QLibrary;
+QT_END_NAMESPACE
+
+namespace dfmplugin_encrypt_manager {
+
+class TPMWork : public QObject
+{
+ Q_OBJECT
+public:
+ explicit TPMWork(QObject *parent = nullptr);
+ ~TPMWork();
+ bool checkTPMAvailable();
+ bool getRandom(int size, QString *output);
+ bool isSupportAlgo(const QString &algoName, bool *support);
+ bool encrypt(const QString &hashAlgo, const QString &keyAlgo,
+ const QString &keyPin, const QString &password,
+ const QString &dirPath);
+ bool decrypt(const QString &keyPin, const QString &dirPath, QString *psw);
+
+ int checkTPMAvailbableByTools();
+ int getRandomByTools(int size, QString *output);
+ int isSupportAlgoByTools(const QString &algoName, bool *support);
+ int encryptByTools(const EncryptParams ¶ms);
+ int decryptByTools(const DecryptParams ¶ms, QString *pwd);
+ int ownerAuthStatus();
+
+private:
+ bool initTpm2(const QString &hashAlgo, const QString &keyAlgo,
+ const QString &keyPin, const QString &dirPath);
+
+ QLibrary *tpmLib { nullptr };
+};
+
+}
+
+#endif // TPMWORK_H
diff --git a/src/services/CMakeLists.txt b/src/services/CMakeLists.txt
index 2eb4da9e57..7ab87fef06 100644
--- a/src/services/CMakeLists.txt
+++ b/src/services/CMakeLists.txt
@@ -4,6 +4,7 @@ add_subdirectory(accesscontrol)
add_subdirectory(sharecontrol)
add_subdirectory(mountcontrol)
add_subdirectory(textindex)
+add_subdirectory(diskencrypt)
# 安全加固
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/deepin-service-group@.service.d DESTINATION /etc/systemd/system/)
diff --git a/src/services/diskencrypt/CMakeLists.txt b/src/services/diskencrypt/CMakeLists.txt
new file mode 100644
index 0000000000..954e320d30
--- /dev/null
+++ b/src/services/diskencrypt/CMakeLists.txt
@@ -0,0 +1,67 @@
+cmake_minimum_required(VERSION 3.0)
+
+set(BIN_NAME "deepin-diskencrypt-service")
+project(${BIN_NAME})
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(DiskEncrypt_XML ${DFM_DBUS_XML_DIR}/org.deepin.Filemanager.DiskEncrypt.xml)
+
+find_package(Qt5 REQUIRED COMPONENTS Core Concurrent DBus)
+find_package(deepin-qdbus-service REQUIRED)
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(CryptSetup REQUIRED libcryptsetup)
+pkg_check_modules(PolkitAgent REQUIRED polkit-agent-1 IMPORTED_TARGET)
+pkg_check_modules(PolkitQt5 REQUIRED polkit-qt5-1 IMPORTED_TARGET)
+
+add_definitions(-DSERVICE_CONFIG_DIR="${CMAKE_INSTALL_PREFIX}/share/deepin-service-manager/")
+
+file(GLOB_RECURSE SRCS
+ "${CMAKE_CURRENT_SOURCE_DIR}/*.h"
+ "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
+)
+
+# generate dbus xml and adaptor
+# DBus: DiskEncryptDBus
+qt5_generate_dbus_interface(
+ diskencryptdbus.h
+ ${DiskEncrypt_XML}
+ OPTIONS -M -S
+)
+qt5_add_dbus_adaptor(SRCS
+ ${DiskEncrypt_XML}
+ diskencryptdbus.h
+ DiskEncryptDBus)
+
+
+add_executable(${BIN_NAME}
+ ${SRCS}
+)
+
+target_link_libraries(${BIN_NAME} PRIVATE
+ Qt5::Core
+ Qt5::Concurrent
+ Qt5::DBus
+ DFM::base
+ PkgConfig::PolkitAgent
+ PkgConfig::PolkitQt5
+ ${CryptSetup_LIBRARIES}
+ ${deepin-qdbus-service_LIBRARIES}
+)
+
+target_include_directories(${BIN_NAME}
+ PUBLIC
+ ${PROJECT_SOURCE_DIR}
+ ${CryptSetup_INCLUDE_DIRS}
+ ${deepin-qdbus-service_INCLUDE_DIR}
+)
+
+install(TARGETS ${BIN_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
+install(FILES ${PROJECT_NAME}.json DESTINATION share/deepin-service-manager/other/)
+install(FILES org.deepin.filemanager.diskencrypt.conf DESTINATION share/dbus-1/system.d/)
+install(FILES org.deepin.Filemanager.DiskEncrypt.service DESTINATION share/dbus-1/system-services/)
+
+set(PolicyDir "${CMAKE_INSTALL_PREFIX}/share/polkit-1/actions")
+install(FILES polkit/policy/org.deepin.filemanager.diskencrypt.policy
+ DESTINATION ${PolicyDir})
+install(FILES polkit/rules/99-dde-file-manager-encrypt.pkla
+ DESTINATION /etc/polkit-1/localauthority/10-vendor.d)
diff --git a/src/services/diskencrypt/deepin-diskencrypt-service.json b/src/services/diskencrypt/deepin-diskencrypt-service.json
new file mode 100644
index 0000000000..36c0a12d86
--- /dev/null
+++ b/src/services/diskencrypt/deepin-diskencrypt-service.json
@@ -0,0 +1,10 @@
+{
+ "name": "org.deepin.Filemanager.DiskEncrypt",
+ "policyStartType": "OnDemand",
+ "idleTime": 10,
+ "policy": [
+ {
+ "path": "/org/deepin/Filemanager/DiskEncrypt"
+ }
+ ]
+}
diff --git a/src/services/diskencrypt/diskencrypt_global.h b/src/services/diskencrypt/diskencrypt_global.h
new file mode 100644
index 0000000000..c4e7954a63
--- /dev/null
+++ b/src/services/diskencrypt/diskencrypt_global.h
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef DAEMONPLUGIN_FILE_ENCRYPT_GLOBAL_H
+#define DAEMONPLUGIN_FILE_ENCRYPT_GLOBAL_H
+
+#include "globaltypesdefine.h"
+
+#include
+#include
+#include
+
+#if defined(DAEMONPLUGIN_FILE_ENCRYPT_LIBRARY)
+# define DAEMONPLUGIN_FILE_ENCRYPT_EXPORT Q_DECL_EXPORT
+#else
+# define DAEMONPLUGIN_FILE_ENCRYPT_EXPORT Q_DECL_IMPORT
+#endif
+
+#define FILE_ENCRYPT_NS daemonplugin_file_encrypt
+#define FILE_ENCRYPT_BEGIN_NS namespace FILE_ENCRYPT_NS {
+#define FILE_ENCRYPT_END_NS }
+#define FILE_ENCRYPT_USE_NS using namespace FILE_ENCRYPT_NS;
+
+FILE_ENCRYPT_BEGIN_NS
+
+struct EncryptParams
+{
+ QString device;
+ QString passphrase;
+ QString cipher;
+ QString recoveryPath;
+ QString tpmToken;
+
+ bool isValid() const
+ {
+ return !(device.isEmpty()
+ && passphrase.isEmpty()
+ && cipher.isEmpty());
+ }
+};
+
+inline constexpr char kDecryptHeaderPrefix[] { "dm_header_decrypt_" };
+
+FILE_ENCRYPT_END_NS
+#endif // DAEMONPLUGIN_FILE_ENCRYPT_GLOBAL_H
diff --git a/src/services/diskencrypt/diskencryptdbus.cpp b/src/services/diskencrypt/diskencryptdbus.cpp
new file mode 100644
index 0000000000..83bc5df615
--- /dev/null
+++ b/src/services/diskencrypt/diskencryptdbus.cpp
@@ -0,0 +1,464 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "diskencryptdbus.h"
+#include "encrypt/encryptworker.h"
+#include "encrypt/diskencrypt.h"
+#include "notification/notifications.h"
+#include "diskencrypt_global.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+FILE_ENCRYPT_USE_NS
+using namespace disk_encrypt;
+#define JOB_ID QString("job_%1")
+static constexpr char kActionEncrypt[] { "org.deepin.Filemanager.DiskEncrypt.Encrypt" };
+static constexpr char kActionDecrypt[] { "org.deepin.Filemanager.DiskEncrypt.Decrypt" };
+static constexpr char kActionChgPwd[] { "org.deepin.Filemanager.DiskEncrypt.ChangePassphrase" };
+
+ReencryptWorkerV2 *gFstabEncWorker { nullptr };
+
+DiskEncryptDBus::DiskEncryptDBus(QObject *parent)
+ : QDBusService(parent)
+ , QDBusContext()
+{
+ initPolicy(QDBusConnection::SystemBus, QString(SERVICE_CONFIG_DIR) + "other/diskencrypt-service.json");
+
+ dfmmount::DDeviceManager::instance();
+
+ connect(SignalEmitter::instance(), &SignalEmitter::updateEncryptProgress,
+ this, [this](const QString &dev, double progress) {
+ Q_EMIT this->EncryptProgress(dev, deviceName, progress);
+ },
+ Qt::QueuedConnection);
+ connect(SignalEmitter::instance(), &SignalEmitter::updateDecryptProgress,
+ this, [this](const QString &dev, double progress) {
+ Q_EMIT this->DecryptProgress(dev, deviceName, progress);
+ },
+ Qt::QueuedConnection);
+
+ QtConcurrent::run([this] { diskCheck(); });
+ createReencryptDesktop();
+ triggerReencrypt();
+}
+
+DiskEncryptDBus::~DiskEncryptDBus()
+{
+}
+
+QString DiskEncryptDBus::PrepareEncryptDisk(const QVariantMap ¶ms)
+{
+ deviceName = params.value(encrypt_param_keys::kKeyDeviceName).toString();
+ if (!checkAuth(kActionEncrypt)) {
+ Q_EMIT PrepareEncryptDiskResult(params.value(encrypt_param_keys::kKeyDevice).toString(),
+ deviceName,
+ "",
+ -kUserCancelled);
+ return "";
+ }
+
+ auto jobID = JOB_ID.arg(QDateTime::currentMSecsSinceEpoch());
+ PrencryptWorker *worker = new PrencryptWorker(jobID,
+ params,
+ this);
+ connect(worker, &QThread::finished, this, [=] {
+ running = false;
+ int ret = worker->exitError();
+ QString device = params.value(encrypt_param_keys::kKeyDevice).toString();
+
+ qDebug() << "pre encrypt finished"
+ << device
+ << ret;
+
+ Q_EMIT this->PrepareEncryptDiskResult(device,
+ deviceName,
+ jobID,
+ static_cast(ret));
+ if (ret == kSuccess) {
+ qInfo() << "start reencrypt device" << device;
+ triggerReencrypt(device);
+ }
+
+ worker->deleteLater();
+ });
+
+ worker->start();
+ running = true;
+
+ return jobID;
+}
+
+QString DiskEncryptDBus::DecryptDisk(const QVariantMap ¶ms)
+{
+ deviceName = params.value(encrypt_param_keys::kKeyDeviceName).toString();
+ QString dev = params.value(encrypt_param_keys::kKeyDevice).toString();
+ if (!checkAuth(kActionDecrypt)) {
+ Q_EMIT DecryptDiskResult(dev, deviceName, "", -kUserCancelled);
+ return "";
+ }
+
+ auto jobID = JOB_ID.arg(QDateTime::currentMSecsSinceEpoch());
+
+ QString pass = params.value(encrypt_param_keys::kKeyPassphrase).toString();
+ if (dev.isEmpty()
+ || (pass.isEmpty() && !params.value(encrypt_param_keys::kKeyInitParamsOnly).toBool())) {
+ qDebug() << "cannot decrypt, params are not valid";
+ return "";
+ }
+
+ DecryptWorker *worker = new DecryptWorker(jobID, params, this);
+ connect(worker, &QThread::finished, this, [=] {
+ running = false;
+ int ret = worker->exitError();
+ qDebug() << "decrypt device finished:"
+ << dev
+ << ret;
+ Q_EMIT DecryptDiskResult(dev, deviceName, jobID, ret);
+ worker->deleteLater();
+ });
+ worker->start();
+ running = true;
+ return jobID;
+}
+
+QString DiskEncryptDBus::ChangeEncryptPassphress(const QVariantMap ¶ms)
+{
+ deviceName = params.value(encrypt_param_keys::kKeyDeviceName).toString();
+ QString dev = params.value(encrypt_param_keys::kKeyDevice).toString();
+ if (!checkAuth(kActionChgPwd)) {
+ Q_EMIT ChangePassphressResult(dev,
+ deviceName,
+ "",
+ -kUserCancelled);
+ return "";
+ }
+
+ auto jobID = JOB_ID.arg(QDateTime::currentMSecsSinceEpoch());
+ ChgPassWorker *worker = new ChgPassWorker(jobID, params, this);
+ connect(worker, &QThread::finished, this, [=] {
+ running = false;
+ int ret = worker->exitError();
+ QString dev = params.value(encrypt_param_keys::kKeyDevice).toString();
+ qDebug() << "change password finished:"
+ << dev
+ << ret;
+ Q_EMIT ChangePassphressResult(dev, deviceName, jobID, ret);
+ worker->deleteLater();
+ });
+ worker->start();
+ running = true;
+ return jobID;
+}
+
+void DiskEncryptDBus::IgnoreParamRequest()
+{
+ if (gFstabEncWorker)
+ gFstabEncWorker->ignoreParamRequest();
+}
+
+void DiskEncryptDBus::ResumeEncryption(const QString &device)
+{
+ triggerReencrypt(device);
+}
+
+QString DiskEncryptDBus::QueryTPMToken(const QString &device)
+{
+ QString token;
+ disk_encrypt_funcs::bcGetToken(device, &token);
+ return token;
+}
+
+int DiskEncryptDBus::EncryptStatus(const QString &device)
+{
+ EncryptStates states;
+ block_device_utils::bcDevEncryptStatus(device, &states);
+ return states;
+}
+
+void DiskEncryptDBus::SetEncryptParams(const QVariantMap ¶ms)
+{
+ if (!checkAuth(kActionEncrypt)) {
+ Q_EMIT EncryptDiskResult(params.value(encrypt_param_keys::kKeyDevice).toString(),
+ deviceName,
+ -kUserCancelled,
+ "");
+ return;
+ }
+
+ if (!gFstabEncWorker)
+ return;
+
+ gFstabEncWorker->setEncryptParams(params);
+}
+
+bool DiskEncryptDBus::HasPendingTask()
+{
+ QDir d("/boot/usec-crypt/");
+ auto files = d.entryInfoList(QDir::Filter::NoDotAndDotDot | QDir::Filter::Files);
+ for (const auto &file : files) {
+ auto name = file.fileName();
+ // search for decrypt.json, encrypt.json, encrypt_.json
+ if (name.contains(QRegularExpression(R"((decrypt|encrypt|encrypt_.{3,})\.json)")))
+ return true;
+ }
+ return false;
+}
+
+bool DiskEncryptDBus::IsWorkerRunning()
+{
+ return running;
+}
+
+QString DiskEncryptDBus::UnfinishedDecryptJob()
+{
+ QDir d("/boot/usec-crypt/");
+ auto files = d.entryInfoList(QDir::Filter::NoDotAndDotDot | QDir::Filter::Files);
+ for (const auto &file : files) {
+ auto name = file.fileName();
+ if (name.contains(kDecryptHeaderPrefix))
+ return "/dev/" + name.remove(kDecryptHeaderPrefix);
+ }
+ return "";
+}
+
+void DiskEncryptDBus::onFstabDiskEncProgressUpdated(const QString &dev, qint64 offset, qint64 total)
+{
+ Q_EMIT EncryptProgress(currentEncryptingDevice, deviceName, (1.0 * offset) / total);
+}
+
+void DiskEncryptDBus::onFstabDiskEncFinished(const QString &dev, int result, const QString &errstr)
+{
+ qInfo() << "device has been encrypted: " << dev << result << errstr;
+ Q_EMIT EncryptDiskResult(dev, deviceName, result != 0 ? -1000 : 0, "");
+ if (result == 0) {
+ qInfo() << "encrypt finished, remove encrypt config";
+ ::remove(kEncConfigPath);
+ }
+}
+
+bool DiskEncryptDBus::checkAuth(const QString &actID)
+{
+ using namespace PolkitQt1;
+
+ QString appBusName = message().service();
+ if (appBusName.isEmpty())
+ return false;
+
+ // PolkitUnixProcess表示 UNIX 进程的对象。注意:这个设计的对象现在已知已损坏;确定了一种利用 Linux 内核中启动时间延迟的机制。避免调用 `polkit_subject_equal()` 来比较两个进程。
+ Authority::Result result = Authority::instance()->checkAuthorizationSync(actID,
+ SystemBusNameSubject(appBusName),
+ Authority::AllowUserInteraction);
+ return result == Authority::Yes;
+}
+
+bool DiskEncryptDBus::triggerReencrypt(const QString &device)
+{
+ gFstabEncWorker = new ReencryptWorkerV2(this);
+ gFstabEncWorker->loadReencryptConfig(device);
+ connect(gFstabEncWorker, &ReencryptWorkerV2::requestEncryptParams,
+ this, &DiskEncryptDBus::RequestEncryptParams);
+ connect(gFstabEncWorker, &ReencryptWorkerV2::deviceReencryptResult,
+ this, [this](const QString &dev, int code, const QString &msg) {
+ Q_EMIT EncryptDiskResult(dev, deviceName, code, msg);
+ });
+ connect(gFstabEncWorker, &ReencryptWorkerV2::finished,
+ this, [this] {
+ running = false;
+ auto exitCode = gFstabEncWorker->exitError();
+ gFstabEncWorker->deleteLater();
+ gFstabEncWorker = nullptr;
+ if (exitCode == -kIgnoreRequest)
+ return;
+ // pick a new job.
+ const static QRegularExpression reg(R"(encrypt_(.*).json)");
+ QDir usecDir("/boot/usec-crypt");
+ auto files = usecDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
+ for (const auto &file : files) {
+ auto fileName = file.fileName();
+ if (fileName.contains(reg)) {
+ qInfo() << "found new unfinished job:" << fileName;
+ auto match = reg.match(fileName);
+ if (match.hasMatch()) {
+ auto dev = match.captured(1);
+ dev = "/dev/" + dev;
+ triggerReencrypt(dev);
+ return;
+ }
+ }
+ }
+ });
+
+ currentEncryptingDevice = gFstabEncWorker->encryptConfig().devicePath;
+ deviceName = gFstabEncWorker->encryptConfig().deviceName;
+ qInfo() << "about to start encrypting" << currentEncryptingDevice;
+ gFstabEncWorker->start();
+ running = true;
+ return true;
+}
+
+// this is used to create a desktop file into
+// /usr/share/applications/dfm-reencrypt.desktop
+void DiskEncryptDBus::createReencryptDesktop()
+{
+ QFile f(kReencryptDesktopFile);
+ if (f.exists())
+ return;
+
+ QByteArray desktop {
+ "[Desktop Entry]\n"
+ "Categories=System;\n"
+ "Comment=To auto launch reencryption\n"
+ "Exec=/usr/bin/dde-file-manager -d\n"
+ "GenericName=Disk Reencrypt\n"
+ "Icon=dde-file-manager\n"
+ "Name=Disk Reencrypt\n"
+ "Terminal=false\n"
+ "Type=Application\n"
+ "NoDisplay=true\n"
+ "X-AppStream-Ignore=true\n"
+ "X-Deepin-AppID=dde-file-manager\n"
+ "X-Deepin-Vendor=deepin\n"
+ };
+
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qWarning() << "cannot open desktop file to write!";
+ return;
+ }
+ f.write(desktop);
+ f.close();
+
+ qInfo() << "desktop file created.";
+}
+
+// this function should be running in thread.
+// it may take times.
+void DiskEncryptDBus::diskCheck()
+{
+ updateCrypttab();
+}
+
+void DiskEncryptDBus::getDeviceMapper(QMap *dev2uuid,
+ QMap *uuid2dev,
+ QMap *puuid2dev)
+{
+ Q_ASSERT(dev2uuid && uuid2dev);
+ using namespace dfmmount;
+ auto monitor = DDeviceManager::instance()->getRegisteredMonitor(DeviceType::kBlockDevice).objectCast();
+ Q_ASSERT(monitor);
+
+ const QStringList &objPaths = monitor->getDevices();
+ for (const auto &objPath : objPaths) {
+ auto blkPtr = monitor->createDeviceById(objPath).objectCast();
+ if (!blkPtr) continue;
+
+ QString uuid = blkPtr->getProperty(dfmmount::Property::kBlockIDUUID).toString();
+ if (uuid.isEmpty()) continue;
+
+ QString puuid = blkPtr->getProperty(dfmmount::Property::kPartitionUUID).toString();
+
+ QString dev = blkPtr->device();
+ uuid = QString("UUID=") + uuid;
+ dev2uuid->insert(dev, uuid);
+ uuid2dev->insert(uuid, dev);
+ if (!puuid.isEmpty())
+ puuid2dev->insert(QString("PARTUUID=") + puuid, dev);
+ }
+}
+
+bool DiskEncryptDBus::updateCrypttab()
+{
+ qInfo() << "==== start checking crypttab...";
+ QFile crypttab("/etc/crypttab");
+ if (!crypttab.open(QIODevice::ReadWrite)) {
+ qWarning() << "cannot open crypttab for rw";
+ return false;
+ }
+ auto content = crypttab.readAll();
+ crypttab.close();
+
+ bool cryptUpdated = false;
+ QByteArrayList lines = content.split('\n');
+ for (int i = lines.count() - 1; i >= 0; --i) {
+ QString line = lines.at(i);
+ if (line.startsWith("#")) {
+ qInfo() << "==== [ignore] comment:" << line;
+ continue;
+ }
+
+ auto items = line.split(QRegularExpression(R"( |\t)"), QString::SkipEmptyParts);
+ if (items.count() < 2) {
+ lines.removeAt(i);
+ qInfo() << "==== [remove] invalid line:" << line;
+ continue;
+ }
+
+ if (isEncrypted(items.at(0), items.at(1)) == 0) {
+ lines.removeAt(i);
+ cryptUpdated = true;
+ qWarning() << "==== [remove] this item is not encrypted:" << line;
+ continue;
+ }
+
+ qInfo() << "==== [ keep ] device is still encrypted:" << line;
+ }
+
+ qInfo() << "==== end checking crypttab, crypttab is updated:" << cryptUpdated;
+ if (cryptUpdated) {
+ content = lines.join('\n');
+ content.append("\n");
+ if (!crypttab.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qWarning() << "cannot open cryppttab for update";
+ return false;
+ }
+ crypttab.write(content);
+ crypttab.close();
+ }
+ return cryptUpdated;
+}
+
+int DiskEncryptDBus::isEncrypted(const QString &target, const QString &source)
+{
+ return QFile("/dev/mapper/" + target).exists() ? 1 : 0;
+
+ QMap dev2uuid, uuid2dev, puuid2dev;
+ getDeviceMapper(&dev2uuid, &uuid2dev, &puuid2dev);
+
+ QString dev = source;
+ if (dev.startsWith("UUID")) {
+ dev = uuid2dev.value(dev);
+ if (dev.isEmpty()) {
+ qWarning() << "cannot find device by UUID, device might already decrypted." << source;
+ return 0;
+ }
+ } else if (dev.startsWith("PARTUUID")) {
+ dev = puuid2dev.value(dev);
+ if (dev.isEmpty()) {
+ qWarning() << "cannot find device by PARTUUID, device might already decrypted." << source;
+ return 0;
+ }
+ }
+
+ if (dev.isEmpty()) {
+ qWarning() << "cannot find device:" << target << source;
+ return -1;
+ }
+
+ auto devPtr = block_device_utils::bcCreateBlkDev(dev);
+ if (!devPtr) {
+ qDebug() << "cannot construct device pointer by " << dev;
+ return -2;
+ }
+
+ return devPtr->isEncrypted() ? 1 : 0;
+}
diff --git a/src/services/diskencrypt/diskencryptdbus.h b/src/services/diskencrypt/diskencryptdbus.h
new file mode 100644
index 0000000000..48ca214773
--- /dev/null
+++ b/src/services/diskencrypt/diskencryptdbus.h
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#ifndef DISKENCRYPTDBUS_H
+#define DISKENCRYPTDBUS_H
+
+#include
+#include
+#include
+#include
+
+class DiskEncryptDBus : public QDBusService, public QDBusContext
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.deepin.Filemanager.DiskEncrypt")
+public:
+ explicit DiskEncryptDBus(QObject *parent = nullptr);
+ ~DiskEncryptDBus();
+
+public Q_SLOTS:
+ QString PrepareEncryptDisk(const QVariantMap ¶ms);
+ QString DecryptDisk(const QVariantMap ¶ms);
+ QString ChangeEncryptPassphress(const QVariantMap ¶ms);
+ void IgnoreParamRequest();
+ void ResumeEncryption(const QString &device);
+ void SetEncryptParams(const QVariantMap ¶ms);
+ QString QueryTPMToken(const QString &device);
+ int EncryptStatus(const QString &device);
+ bool HasPendingTask();
+ bool IsWorkerRunning();
+ QString UnfinishedDecryptJob();
+
+Q_SIGNALS:
+ void PrepareEncryptDiskResult(const QString &device, const QString &devName, const QString &jobID, int errCode);
+ void EncryptDiskResult(const QString &device, const QString &devName, int errCode, const QString &msg);
+ void DecryptDiskResult(const QString &device, const QString &devName, const QString &jobID, int errCode);
+ void ChangePassphressResult(const QString &device, const QString &devName, const QString &jobID, int errCode);
+ void EncryptProgress(const QString &device, const QString &devName, double progress);
+ void DecryptProgress(const QString &device, const QString &devName, double progress);
+ void RequestEncryptParams(const QVariantMap &encConfig);
+
+private Q_SLOTS:
+ void onFstabDiskEncProgressUpdated(const QString &dev, qint64 offset, qint64 total);
+ void onFstabDiskEncFinished(const QString &dev, int result, const QString &errstr);
+
+private:
+ bool checkAuth(const QString &actID);
+ void diskCheck();
+ bool triggerReencrypt(const QString &device = QString());
+ void createReencryptDesktop();
+ static void getDeviceMapper(QMap *, QMap *, QMap *);
+ static bool updateCrypttab();
+ static int isEncrypted(const QString &target, const QString &source);
+
+private:
+ QString currentEncryptingDevice;
+ QString deviceName;
+ bool running { false };
+};
+
+#endif // DISKENCRYPTDBUS_H
diff --git a/src/services/diskencrypt/encrypt/diskencrypt.cpp b/src/services/diskencrypt/encrypt/diskencrypt.cpp
new file mode 100644
index 0000000000..91d068501a
--- /dev/null
+++ b/src/services/diskencrypt/encrypt/diskencrypt.cpp
@@ -0,0 +1,1149 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#include "diskencrypt.h"
+#include "fsresize/fsresize.h"
+#include "notification/notifications.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+FILE_ENCRYPT_USE_NS
+using namespace disk_encrypt;
+
+#define CHECK_INT(checkVal, msg, retVal) \
+ if ((checkVal) < 0) { \
+ qWarning() << (msg) << (checkVal); \
+ return retVal; \
+ }
+#define CHECK_BOOL(checkVal, msg, retVal) \
+ if (!(checkVal)) { \
+ qWarning() << (msg); \
+ return retVal; \
+ }
+
+// used to record current reencrypting device.
+QString gCurrReencryptingDevice;
+QString gCurrDecryptintDevice;
+bool gInterruptEncFlag { false };
+
+struct crypt_params_reencrypt *encryptParams()
+{
+ static struct crypt_params_luks2 reencLuks2
+ {
+ .sector_size = 512
+ };
+
+ static struct crypt_params_reencrypt reencParams
+ {
+ .mode = CRYPT_REENCRYPT_ENCRYPT,
+ .direction = CRYPT_REENCRYPT_BACKWARD,
+ .resilience = "datashift",
+ .hash = "sha256",
+ .data_shift = 32 * 1024,
+ .max_hotzone_size = 0,
+ .device_size = 0,
+ .luks2 = &reencLuks2,
+ .flags = CRYPT_REENCRYPT_INITIALIZE_ONLY | CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT
+ };
+ return &reencParams;
+}
+struct crypt_params_reencrypt *decryptParams()
+{
+ static struct crypt_params_reencrypt params
+ {
+ .mode = CRYPT_REENCRYPT_DECRYPT,
+ .direction = CRYPT_REENCRYPT_BACKWARD,
+ .resilience = "checksum",
+ .hash = "sha256",
+ .data_shift = 0,
+ .max_hotzone_size = 0,
+ .device_size = 0
+ };
+ return ¶ms;
+}
+struct crypt_params_reencrypt *resumeParams()
+{
+ static struct crypt_params_reencrypt params
+ {
+ .mode = CRYPT_REENCRYPT_REENCRYPT,
+ .direction = CRYPT_REENCRYPT_BACKWARD,
+ .resilience = "datashift",
+ .hash = "sha256",
+ .data_shift = 32 * 1024,
+ .max_hotzone_size = 0,
+ .device_size = 0,
+ .flags = CRYPT_REENCRYPT_RESUME_ONLY | CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT
+ };
+ return ¶ms;
+}
+void parseCipher(const QString &fullCipher, QString *cipher, QString *mode, int *len)
+{
+ Q_ASSERT(cipher && mode && len);
+ *cipher = fullCipher;
+ *mode = "xts-plain64";
+ *len = 256;
+}
+
+EncryptParams disk_encrypt_utils::bcConvertParams(const QVariantMap ¶ms)
+{
+ auto toString = [¶ms](const QString &key) { return params.value(key).toString(); };
+ return {
+ .device = toString(encrypt_param_keys::kKeyDevice),
+ .passphrase = toString(encrypt_param_keys::kKeyPassphrase), // decode()
+ .cipher = toString(encrypt_param_keys::kKeyCipher),
+ .recoveryPath = toString(encrypt_param_keys::kKeyRecoveryExportPath),
+ .tpmToken = toString(encrypt_param_keys::kKeyTPMToken),
+ };
+}
+
+bool disk_encrypt_utils::bcValidateParams(const EncryptParams ¶ms)
+{
+ if (!params.isValid()) {
+ qWarning() << "params is not valid!";
+ return false;
+ }
+
+ // check whether device exists
+ struct stat blkStat;
+ if (stat(params.device.toStdString().c_str(), &blkStat) != 0) {
+ int errCode = errno;
+ qWarning() << "query stat of device failed:"
+ << params.device
+ << strerror(errCode)
+ << errCode;
+ return false;
+ }
+ if (!S_ISBLK(blkStat.st_mode)) {
+ qWarning() << "device is not a block!"
+ << params.device
+ << blkStat.st_mode;
+ return false;
+ }
+
+ // check if is valid path.
+ if (!params.recoveryPath.isEmpty()
+ && access(params.recoveryPath.toStdString().c_str(), F_OK) != 0) {
+ qWarning() << "recovery export path is not valid!"
+ << params.recoveryPath;
+ return false;
+ }
+
+ return true;
+}
+
+
+QString disk_encrypt_utils::generateRandomString(int length)
+{
+ // 定义字符集
+ const QString charset = QString("0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz");
+
+ QString result;
+ result.reserve(length);
+
+ // 获取全局随机生成器实例
+ QRandomGenerator *generator = QRandomGenerator::global();
+
+ // 生成随机字符串
+ for (int i = 0; i < length; ++i) {
+ int index = generator->bounded(charset.length());
+ result.append(charset.at(index));
+ }
+
+ return result;
+}
+
+QString disk_encrypt_utils::bcGenRecKey()
+{
+ QString recKey;
+ QLibrary lib("usec-recoverykey");
+ dfmbase::FinallyUtil finalClear([&] { if (lib.isLoaded()) lib.unload(); });
+
+ if (!lib.load()) {
+ qWarning() << "libusec-recoverykey load failed. use default generator";
+ recKey = generateRandomString();
+ return recKey;
+ }
+
+ typedef int (*FnGenKey)(char *, const size_t, const size_t);
+ FnGenKey fn = (FnGenKey)(lib.resolve("usec_get_recovery_key"));
+ if (!fn) {
+ qWarning() << "libusec-recoverykey resolve failed. use uuid as recovery key";
+ return recKey;
+ }
+
+ static const size_t kRecoveryKeySize = 24;
+ char genKey[kRecoveryKeySize + 1];
+ int ret = fn(genKey, kRecoveryKeySize, 1);
+ if (ret != 0) {
+ qWarning() << "libusec-recoverykey generate failed. use uuid as recovery key";
+ return recKey;
+ }
+
+ recKey = genKey;
+ return recKey;
+}
+
+int disk_encrypt_funcs::bcInitHeaderFile(const EncryptParams ¶ms,
+ QString &headerPath, int *keyslotCipher, int *keyslotRecKey)
+{
+ if (!disk_encrypt_utils::bcValidateParams(params))
+ return -kErrorParamsInvalid;
+
+ auto status = block_device_utils::bcDevEncryptVersion(params.device);
+ if (status != kNotEncrypted) {
+ qWarning() << "cannot encrypt device:"
+ << params.device
+ << status;
+ return -kErrorDeviceEncrypted;
+ }
+
+ if (block_device_utils::bcIsMounted(params.device)) {
+ qWarning() << "device is already mounted, cannot encrypt";
+ return -kErrorDeviceMounted;
+ }
+
+ int err = bcDoSetupHeader(params, &headerPath, keyslotCipher, keyslotRecKey);
+ return err;
+}
+
+int disk_encrypt_funcs::bcDoSetupHeader(const EncryptParams ¶ms, QString *headerPath, int *keyslotCipher, int *keyslotRecKey)
+{
+ Q_ASSERT(headerPath && keyslotCipher && keyslotRecKey);
+
+ QString localPath;
+ int ret = 0;
+ ret = bcPrepareHeaderFile(params.device, &localPath);
+ if (localPath.isEmpty())
+ return -kErrorCreateHeader;
+
+ fs_resize::shrinkFileSystem_ext(params.device);
+
+ struct crypt_device *cdev { nullptr };
+
+ dfmbase::FinallyUtil finalClear([&] {
+ if (cdev) crypt_free(cdev);
+ if (ret < 0) {
+ ::remove(localPath.toStdString().c_str());
+ fs_resize::expandFileSystem_ext(params.device);
+ }
+ });
+
+ ret = crypt_init(&cdev, localPath.toStdString().c_str());
+ CHECK_INT(ret, "init crypt failed " + params.device, -kErrorInitCrypt);
+
+ crypt_set_rng_type(cdev, CRYPT_RNG_RANDOM);
+
+ ret = crypt_set_data_offset(cdev, 32 * 1024); // offset 32M
+ CHECK_INT(ret, "cannot set offset " + params.device, -kErrorSetOffset);
+
+ QString cipher, mode;
+ int keyLen;
+ parseCipher(params.cipher, &cipher, &mode, &keyLen);
+ qDebug() << "encrypt with cipher:" << cipher << mode << keyLen;
+
+ std::string cDevice = params.device.toStdString();
+ struct crypt_params_luks2 luks2Params = {
+ .data_alignment = 0,
+ .data_device = cDevice.c_str(),
+ .sector_size = 512,
+ .label = nullptr,
+ .subsystem = nullptr
+ };
+ ret = crypt_format(cdev,
+ CRYPT_LUKS2,
+ cipher.toStdString().c_str(),
+ mode.toStdString().c_str(),
+ nullptr,
+ nullptr,
+ keyLen / 8,
+ &luks2Params);
+ CHECK_INT(ret, "format failed " + params.device, -kErrorFormatLuks);
+
+ ret = crypt_keyslot_add_by_volume_key(cdev,
+ CRYPT_ANY_SLOT,
+ nullptr,
+ 0,
+ params.passphrase.toStdString().c_str(),
+ params.passphrase.length());
+ CHECK_INT(ret, "add key failed " + params.device, -kErrorAddKeyslot);
+ *keyslotCipher = ret;
+#if 0
+ if (!params.recoveryPath.isEmpty()) {
+ QString recKey = disk_encrypt_utils::bcGenRecKey();
+ if (!recKey.isEmpty()) {
+ ret = crypt_keyslot_add_by_volume_key(cdev,
+ CRYPT_ANY_SLOT,
+ nullptr,
+ 0,
+ recKey.toStdString().c_str(),
+ recKey.length());
+ if (ret < 0) {
+ qWarning() << "add recovery key failed:"
+ << params.device
+ << ret;
+ }
+ *keyslotRecKey = ret;
+
+ // TODO export key.
+ }
+ }
+#endif
+
+ ret = crypt_reencrypt_init_by_passphrase(cdev,
+ nullptr,
+ params.passphrase.toStdString().c_str(),
+ params.passphrase.length(),
+ CRYPT_ANY_SLOT,
+ 0,
+ cipher.toStdString().c_str(),
+ mode.toStdString().c_str(),
+ encryptParams());
+ CHECK_INT(ret, "init reencryption failed " + params.device, -kErrorInitReencrypt);
+
+ // active device for expanding fs.
+ QString activeDev = QString("dm-%1").arg(params.device.mid(5));
+ ret = crypt_activate_by_passphrase(cdev,
+ activeDev.toStdString().c_str(),
+ CRYPT_ANY_SLOT,
+ params.passphrase.toStdString().c_str(),
+ params.passphrase.length(),
+ CRYPT_ACTIVATE_NO_JOURNAL);
+ CHECK_INT(ret, "acitve device failed " + params.device + activeDev, -kErrorActive);
+
+ fs_resize::expandFileSystem_ext(QString("/dev/mapper/%1").arg(activeDev));
+ ret = crypt_deactivate(nullptr, activeDev.toStdString().c_str());
+ CHECK_INT(ret, "deacitvi device failed " + params.device, -kErrorDeactive);
+
+ *headerPath = localPath;
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcInitHeaderDevice(const QString &device,
+ const QString &passphrase,
+ const QString &headerPath)
+{
+ Q_ASSERT_X(!headerPath.isEmpty() && !device.isEmpty(),
+ "input params cannot be empty!", "");
+
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {
+ if (cdev) crypt_free(cdev);
+ if (!headerPath.isEmpty()) ::remove(headerPath.toStdString().c_str());
+ });
+
+ int ret = crypt_init(&cdev, device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_header_restore(cdev,
+ CRYPT_LUKS2,
+ headerPath.toStdString().c_str());
+ CHECK_INT(ret, "restore header failed " + device + headerPath, -kErrorRestoreFromFile);
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcPrepareHeaderFile(const QString &device, QString *headerPath)
+{
+ Q_ASSERT(headerPath);
+ QString localPath = QString("/tmp/%1_luks2_pre_enc").arg(device.mid(5));
+ int fd = open(localPath.toStdString().c_str(),
+ O_CREAT | O_EXCL | O_WRONLY,
+ S_IRUSR | S_IWUSR);
+ CHECK_INT(fd, "create tmp file failed " + device + strerror(errno), -kErrorOpenFileFailed);
+
+ int ret = posix_fallocate(fd, 0, 32 * 1024 * 1024);
+ close(fd);
+ CHECK_BOOL(ret == 0, "allocate file failed " + localPath, -kErrorCreateHeader);
+ *headerPath = localPath;
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcDecryptDevice(const QString &device,
+ const QString &passphrase)
+{
+ // backup header first
+ dfmbase::FinallyUtil finalClear([&] {
+ gCurrDecryptintDevice.clear();
+ });
+ gCurrDecryptintDevice = device;
+
+ QString headerPath;
+ int ret = bcBackupCryptHeader(device, headerPath);
+ CHECK_INT(ret, "backup header failed " + device, -kErrorBackupHeader);
+
+ int status = bcReadHeader(headerPath);
+ if (status != kDecryptFully) {
+ ret = bcDoDecryptDevice(device, passphrase, headerPath);
+ CHECK_INT(ret, "decrypt failed " + device, -kErrorDecryptFailed);
+ }
+
+ bool res = block_device_utils::bcMoveFsForward(device);
+ CHECK_BOOL(res, "recovery fs failed " + device, -kErrorResizeFs);
+
+ if (!headerPath.isEmpty())
+ ::remove(headerPath.toStdString().c_str());
+
+ return 0;
+}
+
+int disk_encrypt_funcs::bcBackupCryptHeader(const QString &device, QString &headerPath)
+{
+ headerPath = "/boot/usec-crypt/" + QString(kDecryptHeaderPrefix) + device.mid(5);
+ struct crypt_device *cdev = nullptr;
+ dfmbase::FinallyUtil finalClear([&] { if (cdev) crypt_free(cdev); });
+
+ if (QFile(headerPath).exists()) {
+ qInfo() << "header exists" << headerPath;
+ return 0;
+ }
+
+ int ret = crypt_init(&cdev, device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_header_backup(cdev,
+ nullptr,
+ headerPath.toStdString().c_str());
+ CHECK_INT(ret, "backup header failed " + device, -kErrorBackupHeader);
+ return 0;
+}
+
+int disk_encrypt_funcs::bcResumeReencrypt(const QString &device,
+ const QString &passphrase,
+ const QString &clearDev,
+ bool expandFs)
+{
+ qDebug() << "start resume encryption for device"
+ << device;
+ gCurrReencryptingDevice = device;
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {
+ if (cdev) crypt_free(cdev);
+ gCurrDecryptintDevice.clear();
+ });
+
+ int ret = crypt_init_data_device(&cdev,
+ device.toStdString().c_str(),
+ device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ uint32_t flags;
+ ret = crypt_persistent_flags_get(cdev,
+ CRYPT_FLAGS_REQUIREMENTS,
+ &flags);
+ CHECK_INT(ret, "read flags failed " + device, -kErrorGetReencryptFlag);
+ CHECK_BOOL(flags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT,
+ "wrong flags " + device + " flags " + QString::number(flags),
+ -kErrorWrongFlags);
+
+ std::string _clearDev = clearDev.toStdString();
+ const char *__clearDev = clearDev.isEmpty() ? nullptr : _clearDev.c_str();
+ ret = crypt_reencrypt_init_by_passphrase(cdev,
+ __clearDev,
+ passphrase.toStdString().c_str(),
+ passphrase.length(),
+ CRYPT_ANY_SLOT,
+ CRYPT_ANY_SLOT,
+ nullptr,
+ nullptr,
+ resumeParams());
+ CHECK_INT(ret, "init reencrypt failed " + device, -kErrorInitReencrypt);
+
+ ret = crypt_reencrypt(cdev, bcEncryptProgress);
+ CHECK_INT(ret, "start resume failed " + device, -kErrorReencryptFailed);
+
+ if (!expandFs)
+ return kSuccess;
+
+ // active device for expanding fs.
+ QString activeDev = QString("dm-%1").arg(device.mid(5));
+ ret = crypt_activate_by_passphrase(cdev,
+ activeDev.toStdString().c_str(),
+ CRYPT_ANY_SLOT,
+ passphrase.toStdString().c_str(),
+ passphrase.length(),
+ CRYPT_ACTIVATE_NO_JOURNAL);
+ CHECK_INT(ret, "acitve device failed " + device + activeDev, -kErrorActive);
+
+ fs_resize::expandFileSystem_ext(QString("/dev/mapper/%1").arg(activeDev));
+
+ ret = crypt_deactivate(nullptr,
+ activeDev.toStdString().c_str());
+ CHECK_INT(ret, "deacitvi device failed " + device, -kErrorDeactive);
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcEncryptProgress(uint64_t size, uint64_t offset, void *)
+{
+ Q_EMIT SignalEmitter::instance()->updateEncryptProgress(gCurrReencryptingDevice,
+ double(offset) / size);
+ return 0;
+}
+
+int disk_encrypt_funcs::bcDecryptProgress(uint64_t size, uint64_t offset, void *)
+{
+ Q_EMIT SignalEmitter::instance()->updateDecryptProgress(gCurrDecryptintDevice,
+ double(offset) / size);
+ return 0;
+}
+
+int disk_encrypt_funcs::bcChangePassphrase(const QString &device, const QString &oldPassphrase, const QString &newPassphrase, int *keyslot)
+{
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {if (cdev) crypt_free(cdev); });
+
+ int ret = crypt_init_data_device(&cdev, device.toStdString().c_str(), nullptr);
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ ret = crypt_keyslot_change_by_passphrase(cdev,
+ CRYPT_ANY_SLOT,
+ CRYPT_ANY_SLOT,
+ oldPassphrase.toStdString().c_str(),
+ oldPassphrase.length(),
+ newPassphrase.toStdString().c_str(),
+ newPassphrase.length());
+ CHECK_INT(ret, "change passphrase failed " + device, -kErrorChangePassphraseFailed);
+ Q_ASSERT(keyslot);
+ *keyslot = ret;
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcChangePassphraseByRecKey(const QString &device, const QString &recoveryKey, const QString &newPassphrase, int *keyslot)
+{
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {if (cdev) crypt_free(cdev); });
+
+ int ret = crypt_init_data_device(&cdev,
+ device.toStdString().c_str(),
+ /*device.toStdString().c_str()*/ nullptr);
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ ret = crypt_keyslot_add_by_passphrase(cdev,
+ CRYPT_ANY_SLOT,
+ recoveryKey.toStdString().c_str(),
+ recoveryKey.length(),
+ newPassphrase.toStdString().c_str(),
+ newPassphrase.length());
+ CHECK_INT(ret, "change passphrase by rec key failed " + device, -kErrorAddKeyslot);
+ Q_ASSERT(keyslot);
+ *keyslot = ret;
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcGetToken(const QString &device, QString *tokenJson)
+{
+ Q_ASSERT(tokenJson);
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {if (cdev) crypt_free(cdev); });
+
+ int ret = crypt_init(&cdev,
+ device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ for (int i = 0; i < 32 /* LUKS2_TOKENS_MAX */; ++i) {
+ const char *token { nullptr };
+ if ((ret = crypt_token_json_get(cdev, i, &token)) < 0)
+ continue;
+ QString json(token);
+ if (json.contains("usec-tpm2")) {
+ // qInfo() << "found token:" << json;
+ QJsonDocument doc = QJsonDocument::fromJson(token);
+ QJsonObject obj = doc.object();
+ obj.insert("token_index", i);
+ doc.setObject(obj);
+ *tokenJson = doc.toJson();
+ return kSuccess;
+ }
+ }
+
+ qInfo() << "token not found." << device;
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcSetToken(const QString &device, const QString &token)
+{
+ if (token.isEmpty())
+ return 0;
+
+ QJsonDocument doc = QJsonDocument::fromJson(token.toLocal8Bit());
+ QJsonObject obj = doc.object();
+ int tokenIndex = obj.value("token_index").toInt(CRYPT_ANY_TOKEN);
+
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {if (cdev) crypt_free(cdev); });
+
+ int ret = crypt_init(&cdev,
+ device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ ret = crypt_token_json_set(cdev,
+ tokenIndex,
+ token.toStdString().c_str());
+ CHECK_INT(ret, "set token failed " + device, -kErrorSetTokenFailed);
+ return 0;
+}
+
+EncryptVersion block_device_utils::bcDevEncryptVersion(const QString &device)
+{
+ auto blkDev = block_device_utils::bcCreateBlkDev(device);
+ if (!blkDev) {
+ qWarning() << "cannot create block device handler:"
+ << device;
+ return kVersionUnknown;
+ }
+
+ const QString &idType = blkDev->getProperty(dfmmount::Property::kBlockIDType).toString();
+ const QString &idVersion = blkDev->getProperty(dfmmount::Property::kBlockIDVersion).toString();
+
+ if (idType == "crypto_LUKS") {
+ if (idVersion == "1")
+ return kVersionLUKS1;
+ if (idVersion == "2")
+ return kVersionLUKS2;
+ return kVersionLUKSUnknown;
+ }
+
+ if (blkDev->isEncrypted())
+ return kVersionUnknown;
+
+ // TODO: this should be completed, not only LUKS encrypt.
+
+ return kNotEncrypted;
+}
+
+DevPtr block_device_utils::bcCreateBlkDev(const QString &device)
+{
+ auto mng = dfmmount::DDeviceManager::instance();
+ Q_ASSERT_X(mng, "cannot create device manager", "");
+ auto blkMonitor = mng->getRegisteredMonitor(dfmmount::DeviceType::kBlockDevice)
+ .objectCast();
+ Q_ASSERT_X(blkMonitor, "cannot get valid device monitor", "");
+
+ auto blkDevs = blkMonitor->resolveDeviceNode(device, {});
+ if (blkDevs.isEmpty()) {
+ qWarning() << "cannot resolve device from" << device;
+ return nullptr;
+ }
+
+ auto blkDev = blkMonitor->createDeviceById(blkDevs.constFirst());
+ if (!blkDev) {
+ qWarning() << "cannot create device by" << blkDevs.constFirst();
+ return nullptr;
+ }
+ return blkDev.objectCast();
+}
+
+bool block_device_utils::bcIsMounted(const QString &device)
+{
+ auto blkDev = block_device_utils::bcCreateBlkDev(device);
+ if (!blkDev) {
+ qWarning() << "cannot create block device handler:"
+ << device;
+ return false;
+ }
+ return !blkDev->mountPoints().isEmpty();
+}
+
+int block_device_utils::bcDevEncryptStatus(const QString &device, EncryptStates *status)
+{
+ Q_ASSERT(status);
+ *status = kStatusUnknown;
+
+ auto version = bcDevEncryptVersion(device);
+ if (version == kNotEncrypted) {
+ *status = kStatusNotEncrypted;
+ return kSuccess;
+ }
+
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {if (cdev) crypt_free(cdev); });
+
+ int ret = 0;
+
+ QString backHeader = "/boot/usec-crypt/" + QString(kDecryptHeaderPrefix) + device.mid(5);
+ if (QFile(backHeader).exists()) {
+ ret = crypt_init_data_device(&cdev,
+ backHeader.toStdString().c_str(),
+ device.toStdString().c_str());
+ } else {
+ ret = crypt_init(&cdev,
+ device.toStdString().c_str());
+ }
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ crypt_params_reencrypt param;
+ int state = crypt_reencrypt_status(cdev, ¶m);
+ if (state == CRYPT_REENCRYPT_NONE) {
+ *status = kStatusFinished;
+ return kSuccess;
+ }
+
+ if (param.mode == CRYPT_REENCRYPT_ENCRYPT)
+ *status = kStatusEncrypt;
+ else if (param.mode == CRYPT_REENCRYPT_DECRYPT)
+ *status = kStatusDecrypt;
+
+ uint32_t flags;
+ ret = crypt_persistent_flags_get(cdev,
+ CRYPT_FLAGS_REQUIREMENTS,
+ &flags);
+ CHECK_INT(ret, "get device flag failed " + device, -kErrorGetReencryptFlag);
+
+ if (flags & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT)
+ *status |= kStatusOffline;
+ if (flags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT)
+ *status |= kStatusOnline;
+ if (flags & CRYPT_REQUIREMENT_UNKNOWN)
+ *status = kStatusUnknown;
+
+ if (*status & (kStatusOnline | kStatusEncrypt)) {
+ if (!disk_encrypt_utils::bcHasEncryptConfig(device))
+ *status |= kStatusNoEncryptConfig;
+ }
+
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcSetLabel(const QString &device, const QString &label)
+{
+
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {if (cdev) crypt_free(cdev); });
+
+ int ret = crypt_init(&cdev,
+ device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ ret = crypt_set_label(cdev, label.toStdString().c_str(), nullptr);
+ CHECK_INT(ret, "set label failed " + device, -kErrorSetLabel);
+
+ return kSuccess;
+}
+
+bool disk_encrypt_utils::bcReadEncryptConfig(disk_encrypt::EncryptConfig *config, const QString &device)
+{
+ Q_ASSERT(config);
+
+ QString encryptConfigPath = kEncConfigPath;
+ if (!device.isEmpty())
+ encryptConfigPath = kEncConfigDevicePath.arg(device.mid(5));
+
+ QFile encConfig(encryptConfigPath);
+ if (!encConfig.exists()) {
+ qInfo() << "the encrypt config file doesn't exist";
+ if (encryptConfigPath != kEncConfigPath) {
+ qInfo() << "try trigger default encrypt device.";
+ return bcReadEncryptConfig(config, "");
+ }
+ return false;
+ }
+
+ if (!encConfig.open(QIODevice::ReadOnly)) {
+ qWarning() << "encrypt config file open failed!";
+ return false;
+ }
+
+ QJsonDocument doc = QJsonDocument::fromJson(encConfig.readAll());
+ encConfig.close();
+ auto obj = doc.object();
+
+ config->cipher = obj.value("cipher").toString();
+ config->device = obj.value("device").toString();
+ config->mountPoint = obj.value("device-mountpoint").toString();
+ config->deviceName = obj.value("device-name").toString();
+ config->devicePath = obj.value("device-path").toString();
+ config->keySize = obj.value("key-size").toString();
+ config->mode = obj.value("mode").toString();
+ config->recoveryPath = obj.value("recoverykey-path").toString();
+ // config->tpmConfig = obj.value("tpm-config");// no tpmconfig will be set in pre-encrypt phase
+ config->clearDev = obj.value("volume").toString();
+ config->configPath = encryptConfigPath;
+ config->clearDevUUID = obj.value("clear-device-uuid").toString();
+ config->isDetachedHeader = obj.value("is-detached-header").toBool();
+ config->fsUuid = obj.value("file-system-uuid").toString();
+
+ return true;
+}
+
+QDBusReply utils::inhibit(const QString &message)
+{
+ QDBusInterface iface("org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ QDBusConnection::systemBus());
+ QVariantList args;
+ args << QString("shutdown:sleep:")
+ << QString("file-manager-daemon")
+ << QString(message)
+ << QString("block");
+ return iface.callWithArgumentList(QDBus::Block, "Inhibit", args);
+}
+
+int disk_encrypt_funcs::bcOpenDevice(const QString &device, const QString &activeName)
+{
+ struct crypt_device *cdev { nullptr };
+ dfmbase::FinallyUtil finalClear([&] {if (cdev) crypt_free(cdev); });
+
+ int ret = crypt_init(&cdev,
+ device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ auto status = crypt_status(cdev, activeName.toStdString().c_str());
+ if (status == CRYPT_INACTIVE) {
+ // try unlock by empty passphrase to repair reencryption.
+ ret = crypt_activate_by_passphrase(cdev, activeName.toStdString().c_str(),
+ CRYPT_ANY_SLOT,
+ "",
+ 0,
+ CRYPT_ACTIVATE_NO_JOURNAL);
+ CHECK_INT(ret, "open device failed " + device, -kErrorActive);
+
+ // close device avoid operating.
+ ret = crypt_deactivate(cdev, activeName.toStdString().c_str());
+ CHECK_INT(ret, "close device failed " + device, -kErrorDeactive);
+ } else if (status == CRYPT_INVALID) {
+ qCritical() << "device encrypt status is invalid!" << device;
+ return -kErrorActive;
+ }
+
+ return kSuccess;
+}
+
+bool disk_encrypt_utils::bcSaveRecoveryKey(const QString &dev, const QString &key, const QString &path)
+{
+ if (!QDir(path).exists()) {
+ qWarning() << "export path not exists!" << path;
+ return false;
+ }
+
+ QString recFileName = QString("%1/%2_recovery_key.txt")
+ .arg(path)
+ .arg(dev.mid(5));
+ QFile f(recFileName);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qWarning() << "cannot open file for write recovery key" << recFileName;
+ return false;
+ }
+
+ if (f.write(key.toLocal8Bit()) != key.length()) {
+ qWarning() << "write length not correct!";
+ f.close();
+ return false;
+ }
+ f.close();
+
+ qInfo() << "recovery key has been wrote to" << recFileName;
+ return true;
+}
+
+bool disk_encrypt_utils::bcHasEncryptConfig(const QString &dev)
+{
+ QFile f(disk_encrypt::kEncConfigDevicePath.arg(dev.mid(5)));
+ if (f.exists())
+ return true;
+
+ f.setFileName(disk_encrypt::kEncConfigPath);
+ if (!f.exists())
+ return false;
+
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning() << "cannot open config file for read!";
+ return false;
+ }
+ QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
+ f.close();
+ auto obj = doc.object();
+ const QString &devPath = obj.value("device-path").toString();
+ return devPath == dev;
+}
+
+quint64 block_device_utils::bcGetBlockSize(const QString &device)
+{
+ auto dev = bcCreateBlkDev(device);
+ if (!dev)
+ return 0;
+ return dev->getProperty(dfmmount::Property::kPartitionSize).toULongLong();
+}
+
+bool block_device_utils::bcMoveFsForward(const QString &device)
+{
+ static const quint64 kStepSize = 16 * 1024 * 1024; // luks header size.
+
+ QString dev(device);
+ QString logFilePath("/boot/usec-crypt/dfm_mv_fs_" + dev.replace("/", "_"));
+
+ QFile logFile(logFilePath);
+ QFile blockFile(device);
+ char *buf = new char[kStepSize];
+
+ auto clearMem = [&] {
+ if (logFile.isOpen())
+ logFile.close();
+ if (blockFile.isOpen())
+ blockFile.close();
+ delete[] buf;
+ };
+
+ if (!logFile.exists()) {
+ if (!logFile.open(QIODevice::Truncate | QIODevice::ReadWrite)) {
+ qWarning() << "cannot create log file!" << logFilePath;
+ clearMem();
+ return false;
+ }
+ logFile.close();
+ }
+ if (!logFile.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
+ qWarning() << "cannot open log file!" << logFilePath;
+ clearMem();
+ return false;
+ }
+
+ if (!blockFile.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
+ qWarning() << "cannot open device!" << device;
+ clearMem();
+ return false;
+ }
+
+ // calc total move counts.
+ quint64 partSize = block_device_utils::bcGetBlockSize(device);
+ if (partSize == 0) {
+ qWarning() << "get block size failed!";
+ clearMem();
+ return false;
+ }
+ quint64 mvCount = partSize / kStepSize;
+ if (partSize % kStepSize) mvCount += 1;
+
+ // read break point.
+ auto records = logFile.readAll().split(',');
+ quint64 lastMovedIndex = (records.count() > 0) ? records.last().toULongLong() : 0;
+
+ // start move segments
+ disk_encrypt_funcs::bcDecryptProgress(100, 99, nullptr);
+ qApp->processEvents();
+
+ quint64 currMovedIndex = lastMovedIndex + 1;
+ for (; currMovedIndex <= mvCount; ++currMovedIndex, ++lastMovedIndex) {
+ // qInfo() << "moving..." << currMovedIndex << device;
+ // seek current move position
+ if (!blockFile.seek(currMovedIndex * kStepSize)) {
+ qWarning() << "seek pos failed!" << currMovedIndex * kStepSize;
+ clearMem();
+ return false;
+ }
+
+ // read next step
+ memset(buf, 0, kStepSize);
+ quint64 readed = blockFile.read(buf, kStepSize);
+
+ // write to previous step position.
+ if (!blockFile.seek((lastMovedIndex)*kStepSize)) {
+ qWarning() << "seek target failed!" << lastMovedIndex * kStepSize;
+ clearMem();
+ return false;
+ }
+ quint64 wrote = blockFile.write(buf, readed);
+ if (wrote != readed) {
+ qWarning() << "read write size not match!";
+ clearMem();
+ return false;
+ }
+ if (!blockFile.flush() || fsync(blockFile.handle()) != 0) {
+ qWarning() << "cannot flush device file!" << device;
+ clearMem();
+ return false;
+ }
+
+ // recore current index.
+ QString pos = "," + QString::number(currMovedIndex);
+ logFile.write(pos.toLocal8Bit());
+ if (!logFile.flush() || fsync(logFile.handle()) != 0) {
+ qWarning() << "cannot flush log file!" << logFilePath;
+ clearMem();
+ return false;
+ }
+ // qInfo() << "moved..." << currMovedIndex << device;
+ }
+
+ disk_encrypt_funcs::bcDecryptProgress(100, 100, nullptr);
+
+ clearMem();
+
+ // remove log file on success.
+ ::remove(logFilePath.toStdString().c_str());
+
+ // update udev on move finished.
+ ::system("udevadm trigger");
+
+ return true;
+}
+
+int disk_encrypt_funcs::bcDoDecryptDevice(const QString &device, const QString &passphrase, const QString &headerPath)
+{
+ struct crypt_device *cdev = nullptr;
+ dfmbase::FinallyUtil finalClear([&] {
+ if (cdev) crypt_free(cdev);
+ });
+
+ int ret = crypt_init_data_device(&cdev,
+ headerPath.toStdString().c_str(),
+ device.toStdString().c_str());
+ CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt);
+
+ ret = crypt_load(cdev, CRYPT_LUKS, nullptr);
+ CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt);
+
+ uint32_t flags;
+ ret = crypt_persistent_flags_get(cdev,
+ CRYPT_FLAGS_REQUIREMENTS,
+ &flags);
+ CHECK_INT(ret, "get device flag failed " + device, -kErrorGetReencryptFlag);
+ bool underEncrypting = (flags & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT) || (flags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT);
+
+ crypt_params_reencrypt param;
+ ret = crypt_reencrypt_status(cdev, ¶m);
+ CHECK_INT(ret, "check reencrypt status failed" + device, -kErrorCheckReencryptStatus);
+
+ underEncrypting &= (param.mode == CRYPT_REENCRYPT_ENCRYPT);
+ CHECK_BOOL(!underEncrypting,
+ "device is under encrypting... " + device + " the flags are: " + QString::number(flags),
+ -kErrorWrongFlags);
+
+ if (ret == CRYPT_REENCRYPT_CRASH) { // repair is needed.
+ QString dmName = "dm-" + device.mid(5);
+ ret = crypt_activate_by_passphrase(cdev, dmName.toStdString().c_str(),
+ CRYPT_ANY_SLOT,
+ passphrase.toStdString().c_str(),
+ passphrase.length(),
+ CRYPT_ACTIVATE_RECOVERY);
+ CHECK_INT(ret, "open device failed " + device, -kErrorActive);
+
+ // close device avoid operating.
+ ret = crypt_deactivate(cdev, dmName.toStdString().c_str());
+ }
+
+ // if fully decrypted
+
+ ret = crypt_reencrypt_init_by_passphrase(cdev,
+ nullptr,
+ passphrase.toStdString().c_str(),
+ passphrase.length(),
+ CRYPT_ANY_SLOT,
+ CRYPT_ANY_SLOT,
+ nullptr,
+ nullptr,
+ decryptParams());
+ CHECK_INT(ret, "init reencrypt failed " + device, -kErrorWrongPassphrase);
+
+ ret = crypt_reencrypt(cdev, bcDecryptProgress);
+ CHECK_INT(ret, "decrypt failed" + device, -kErrorReencryptFailed);
+
+ return kSuccess;
+}
+
+int disk_encrypt_funcs::bcReadHeader(const QString &header)
+{
+ QFile headerFile(header);
+ if (!headerFile.open(QIODevice::ReadOnly)) {
+ qWarning() << "open header failed!";
+ return kInvalidHeader;
+ }
+
+ headerFile.seek(4096); // header json starts at 4096
+ QString jsonStr = headerFile.readLine();
+ headerFile.close();
+
+ QJsonDocument doc = QJsonDocument::fromJson(jsonStr.toLocal8Bit());
+ auto obj = doc.object();
+
+ // read segments
+ auto segments = obj.value("segments").toObject();
+ if (segments.isEmpty()) {
+ qWarning() << "segments not found";
+ return kInvalidHeader;
+ }
+ bool hasLinear = false, hasCrypt = false;
+ for (auto iter = segments.begin(); iter != segments.end(); ++iter) {
+ auto segment = iter.value().toObject();
+ auto type = segment.value("type").toString();
+ if (type == "linear")
+ hasLinear = true;
+ if (type == "crypt")
+ hasCrypt = true;
+ }
+
+ // read mode
+ QString mode;
+ auto keyslots = obj.value("keyslots").toObject();
+ for (auto iter = keyslots.begin(); iter != keyslots.end(); ++iter) {
+ auto keyslot = iter.value().toObject();
+ if (keyslot.value("type").toString() == "reencrypt") {
+ mode = keyslot.value("mode").toString();
+ break;
+ }
+ }
+
+ if (mode == "encrypt") {
+ if (hasLinear && hasCrypt)
+ return kEncryptInProgress;
+ if (hasLinear)
+ return kEncryptInit;
+ } else if (mode == "decrypt") {
+ if (hasLinear && hasCrypt)
+ return kDecryptInProgress;
+ if (hasCrypt)
+ return kDecryptInit;
+ } else {
+ if (hasLinear && !hasCrypt)
+ return kDecryptFully;
+ if (!hasLinear && hasCrypt)
+ return kEncryptFully;
+ }
+
+ return kInvalidHeader;
+}
diff --git a/src/services/diskencrypt/encrypt/diskencrypt.h b/src/services/diskencrypt/encrypt/diskencrypt.h
new file mode 100644
index 0000000000..2c1d2fd0c6
--- /dev/null
+++ b/src/services/diskencrypt/encrypt/diskencrypt.h
@@ -0,0 +1,87 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#ifndef DISK_ENCRYPT_H
+#define DISK_ENCRYPT_H
+
+#include "diskencrypt_global.h"
+
+#include
+#include
+#include
+
+namespace dfmmount {
+class DBlockDevice;
+} // namespace dfmmount
+
+FILE_ENCRYPT_BEGIN_NS
+
+enum EncryptVersion {
+ kNotEncrypted,
+ kVersionLUKS1,
+ kVersionLUKS2,
+ kVersionLUKSUnknown,
+
+ kVersionUnknown = 10000,
+}; // enum EncryptVersion
+
+enum HeaderStatus {
+ kInvalidHeader = -1,
+ kEncryptInit,
+ kEncryptInProgress,
+ kEncryptFully,
+ kDecryptInit,
+ kDecryptInProgress,
+ kDecryptFully,
+};
+
+namespace disk_encrypt_funcs {
+int bcInitHeaderFile(const EncryptParams ¶ms, QString &headerPath, int *keyslotCipher, int *keyslotRecKey);
+int bcGetToken(const QString &device, QString *tokenJson);
+int bcInitHeaderDevice(const QString &device, const QString &passphrase, const QString &headerPath);
+int bcSetToken(const QString &device, const QString &token);
+int bcResumeReencrypt(const QString &device, const QString &passphrase, const QString &clearDev, bool expandFs = true);
+int bcChangePassphrase(const QString &device, const QString &oldPassphrase, const QString &newPassphrase, int *keyslot);
+int bcChangePassphraseByRecKey(const QString &device, const QString &oldPassphrase, const QString &newPassphrase, int *keyslot);
+int bcDecryptDevice(const QString &device, const QString &passphrase);
+int bcDoDecryptDevice(const QString &device, const QString &passphrase, const QString &headerPath);
+int bcBackupCryptHeader(const QString &device, QString &headerPath);
+int bcDoSetupHeader(const EncryptParams ¶ms, QString *headerPath, int *keyslotCipher, int *keyslotRecKey);
+int bcPrepareHeaderFile(const QString &device, QString *headerPath);
+int bcSetLabel(const QString &device, const QString &label);
+int bcOpenDevice(const QString &device, const QString &activeName);
+int bcReadHeader(const QString &header);
+int bcEncryptProgress(uint64_t size, uint64_t offset, void *usrptr);
+int bcDecryptProgress(uint64_t size, uint64_t offset, void *usrptr);
+
+} // namespace disk_encrypt_funcs
+
+namespace disk_encrypt_utils {
+EncryptParams bcConvertParams(const QVariantMap ¶ms);
+bool bcValidateParams(const EncryptParams ¶ms);
+bool bcReadEncryptConfig(disk_encrypt::EncryptConfig *config, const QString &device = QString());
+
+QString generateRandomString(int length = 24);
+QString bcGenRecKey();
+bool bcSaveRecoveryKey(const QString &dev, const QString &key, const QString &path);
+bool bcHasEncryptConfig(const QString &dev);
+} // namespace disk_encrypt_utils
+
+typedef QSharedPointer DevPtr;
+namespace block_device_utils {
+DevPtr bcCreateBlkDev(const QString &device);
+EncryptVersion bcDevEncryptVersion(const QString &device);
+int bcDevEncryptStatus(const QString &device, disk_encrypt::EncryptStates *status);
+bool bcIsMounted(const QString &device);
+quint64 bcGetBlockSize(const QString &device);
+
+bool bcMoveFsForward(const QString &device);
+} // namespace block_device_utils
+
+namespace utils {
+QDBusReply inhibit(const QString &message);
+}
+
+FILE_ENCRYPT_END_NS
+
+#endif // DISK_ENCRYPT_H
diff --git a/src/services/diskencrypt/encrypt/encryptworker.cpp b/src/services/diskencrypt/encrypt/encryptworker.cpp
new file mode 100644
index 0000000000..336fa55427
--- /dev/null
+++ b/src/services/diskencrypt/encrypt/encryptworker.cpp
@@ -0,0 +1,760 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#include "encryptworker.h"
+#include "diskencrypt.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+FILE_ENCRYPT_USE_NS
+using namespace disk_encrypt;
+
+static constexpr char kBootUsecPath[] { "/boot/usec-crypt" };
+
+void createRebootFlagFile(const QString &device)
+{
+ QString dev = device;
+ QString fileName = kRebootFlagFilePrefix + dev.replace("/", "_");
+ QFile f(fileName);
+ if (!f.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
+ qWarning() << "cannot create reboot flag file";
+ return;
+ }
+ f.close();
+ qInfo() << "reboot flag created." << fileName;
+}
+
+void createUsecPathIfNotExist()
+{
+ QDir d(kBootUsecPath);
+ if (!d.exists()) {
+ bool ok = d.mkpath(kBootUsecPath);
+ qDebug() << kBootUsecPath << " path created: " << ok;
+ }
+}
+
+PrencryptWorker::PrencryptWorker(const QString &jobID,
+ const QVariantMap ¶ms,
+ QObject *parent)
+ : Worker(jobID, parent),
+ params(params)
+{
+}
+
+void PrencryptWorker::run()
+{
+ auto fd = utils::inhibit(tr("Preparing encrypt..."));
+
+ auto encParams = disk_encrypt_utils::bcConvertParams(params);
+ if (params.value(encrypt_param_keys::kKeyIsDetachedHeader).toBool()) {
+ writeEncryptParams(encParams.device);
+ return;
+ }
+
+ QString mpt = params.value(encrypt_param_keys::kKeyMountPoint).toString();
+ if (kDisabledEncryptPath.contains(mpt, Qt::CaseInsensitive)) {
+ qInfo() << "device mounted at disable list, ignore encrypt.";
+ setExitCode(-kErrorDisabledMountPoint);
+ return;
+ }
+
+ if (params.value(encrypt_param_keys::kKeyInitParamsOnly, false).toBool()) {
+ writeEncryptParams();
+ setFstabTimeout();
+ setExitCode(-kRebootRequired);
+ createRebootFlagFile(params.value(encrypt_param_keys::kKeyDevice).toString());
+ return;
+ }
+
+ if (!disk_encrypt_utils::bcValidateParams(encParams)) {
+ setExitCode(-kErrorParamsInvalid);
+ qDebug() << "invalid params" << params;
+ return;
+ }
+
+ QString localHeaderFile;
+ int err = disk_encrypt_funcs::bcInitHeaderFile(encParams,
+ localHeaderFile,
+ &keyslotCipher,
+ &keyslotRecKey);
+ if (err != kSuccess || localHeaderFile.isEmpty()) {
+ setExitCode(-kErrorCreateHeader);
+ qDebug() << "cannot generate local header"
+ << params;
+ return;
+ }
+
+ int ret = disk_encrypt_funcs::bcInitHeaderDevice(encParams.device,
+ encParams.passphrase,
+ localHeaderFile);
+ if (ret != 0) {
+ setExitCode(-kErrorApplyHeader);
+ qDebug() << "cannot init device encrypt"
+ << params;
+ return;
+ }
+
+ writeEncryptParams(encParams.device);
+
+ if (!encParams.tpmToken.isEmpty()) {
+ QFile f(QString(TOKEN_FILE_PATH).arg(encParams.device.mid(5)));
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qWarning() << "cannot open file to cache token";
+ return;
+ }
+ f.write(encParams.tpmToken.toLocal8Bit());
+ f.flush();
+ f.close();
+ }
+}
+
+int PrencryptWorker::writeEncryptParams(const QString &device)
+{
+ const static QMap encMode {
+ { 0, "pin" },
+ { 1, "tpm-pin" },
+ { 2, "tpm" }
+ };
+
+ QJsonObject obj;
+ QString dev = params.value(encrypt_param_keys::kKeyDevice).toString();
+ QString dmDev = QString("dm-%1").arg(dev.mid(5));
+ if (params.value(encrypt_param_keys::kKeyIsDetachedHeader).toBool())
+ dmDev = params.value(encrypt_param_keys::kKeyPrefferDevice).toString();
+ QString fsUuid = QString("UUID=%1").arg(params.value(encrypt_param_keys::kKeyUUID).toString());
+ QString partUuid = QString("PARTUUID=%1").arg(params.value(encrypt_param_keys::kKeyPartUUID).toString());
+
+ obj.insert("volume", dmDev); // used to name a opened luks device.
+ obj.insert("device", partUuid); // used to locate the backing device.
+ obj.insert("device-path", dev); // used to locate the backing device by device path.
+ obj.insert("device-name", params.value(encrypt_param_keys::kKeyDeviceName).toString()); // the device name display in dde-file-manager
+ obj.insert("device-mountpoint", params.value(encrypt_param_keys::kKeyMountPoint).toString()); // the mountpoint of the device
+ obj.insert("cipher", params.value(encrypt_param_keys::kKeyCipher).toString() + "-xts-plain64");
+ obj.insert("key-size", "256");
+ obj.insert("mode", encMode.value(params.value(encrypt_param_keys::kKeyEncMode).toInt()));
+ obj.insert("clear-device-uuid", params.value(encrypt_param_keys::kKeyClearDevUUID).toString());
+ obj.insert("is-detached-header", params.value(encrypt_param_keys::kKeyIsDetachedHeader).toBool());
+ obj.insert("file-system-uuid", fsUuid);
+
+ QString expPath = params.value(encrypt_param_keys::kKeyRecoveryExportPath).toString();
+ if (!expPath.isEmpty()) {
+ expPath.append(QString("/recovery_key_%1.txt").arg(dev.mid(5)));
+ expPath.replace("//", "/");
+ }
+ obj.insert("recoverykey-path", expPath);
+
+ QJsonDocument tpmConfig = QJsonDocument::fromJson(params.value(encrypt_param_keys::kKeyTPMConfig).toString().toLocal8Bit());
+ obj.insert("tpm-config", tpmConfig.object()); // the tpm info used to decrypt passphrase from tpm.
+ QJsonDocument doc(obj);
+
+ createUsecPathIfNotExist();
+
+ QString configPath = QString("%1/encrypt.json").arg(kBootUsecPath);
+ if (!device.isEmpty() && !params.value(encrypt_param_keys::kKeyIsDetachedHeader).toBool()) {
+ configPath = QString("%1/encrypt_%2.json").arg(kBootUsecPath).arg(device.mid(5));
+ }
+
+ QFile f(configPath);
+ if (f.exists())
+ qInfo() << "has pending job, the pending job will be replaced";
+
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qWarning() << "cannot open file for write!";
+ return -kErrorOpenFileFailed;
+ }
+
+ f.write(doc.toJson());
+ f.flush();
+ f.close();
+ return -kSuccess;
+}
+
+int PrencryptWorker::setFstabTimeout()
+{
+ static const QString kFstabPath { "/etc/fstab" };
+ QFile fstab(kFstabPath);
+ if (!fstab.open(QIODevice::ReadOnly))
+ return kErrorOpenFstabFailed;
+
+ QByteArray fstabContents = fstab.readAll();
+ fstab.close();
+
+ static const QByteArray kTimeoutParam = "x-systemd.device-timeout=0";
+ QString devDesc = params.value(encrypt_param_keys::kKeyDevice).toString();
+ QString devUUID = QString("UUID=%1").arg(params.value(encrypt_param_keys::kKeyUUID).toString());
+ QByteArrayList fstabLines = fstabContents.split('\n');
+ QList fstabItems;
+ bool foundItem = false;
+ for (const QString &line : fstabLines) {
+ QStringList items = line.split(QRegularExpression(R"(\t| )"), QString::SkipEmptyParts);
+ if (items.count() == 6
+ && (items[0] == devDesc || items[0] == devUUID)
+ && !foundItem) {
+
+ if (!items[3].contains(kTimeoutParam)) {
+ items[3] += ("," + kTimeoutParam);
+ foundItem = true;
+ }
+ }
+ fstabItems.append(items);
+ }
+
+ if (foundItem) {
+ QByteArray newContents;
+ for (const auto &items : fstabItems) {
+ newContents += items.join('\t');
+ newContents.append('\n');
+ }
+
+ if (!fstab.open(QIODevice::Truncate | QIODevice::ReadWrite))
+ return kErrorOpenFstabFailed;
+
+ fstab.write(newContents);
+ fstab.flush();
+ fstab.close();
+
+ qDebug() << "old fstab contents:"
+ << fstabContents;
+ qDebug() << "new fstab contents"
+ << newContents;
+ }
+
+ return kSuccess;
+}
+
+DecryptWorker::DecryptWorker(const QString &jobID,
+ const QVariantMap ¶ms,
+ QObject *parent)
+ : Worker(jobID, parent),
+ params(params)
+{
+}
+
+void DecryptWorker::run()
+{
+ auto fd = utils::inhibit(tr("Decrypting..."));
+
+ const QString &device = params.value(encrypt_param_keys::kKeyDevice).toString();
+ EncryptStates status;
+ int ret = block_device_utils::bcDevEncryptStatus(device, &status);
+ if (ret != kSuccess) {
+ qWarning() << "check device status failed!";
+ setExitCode(ret);
+ return;
+ }
+
+ bool isOnlineEncrypting = (status & kStatusOnline) && (status & kStatusEncrypt);
+ if (isOnlineEncrypting) {
+ qWarning() << "encrypt status not finished, cannot decrypt!" << status << device;
+ setExitCode(-kErrorNotFullyEncrypted);
+ return;
+ }
+
+ bool initOnly = params.value(encrypt_param_keys::kKeyInitParamsOnly).toBool();
+ if (initOnly) {
+ writeDecryptParams();
+ const QString &clearDevUUID = params.value(encrypt_param_keys::kKeyClearDevUUID, "").toString();
+ if (!clearDevUUID.isEmpty())
+ ReencryptWorkerV2::setFsPassno(clearDevUUID, "0");
+ setExitCode(-kRebootRequired);
+ createRebootFlagFile(device);
+ return;
+ }
+
+ const QString &passphrase = decryptPasswd(params.value(encrypt_param_keys::kKeyPassphrase).toString());
+ ret = disk_encrypt_funcs::bcDecryptDevice(device, passphrase);
+ if (ret < 0) {
+ setExitCode(ret);
+ qDebug() << "decrypt devcei failed"
+ << device
+ << ret;
+ return;
+ }
+}
+
+int DecryptWorker::writeDecryptParams()
+{
+ createUsecPathIfNotExist();
+
+ QJsonObject obj;
+ QString dev = params.value(encrypt_param_keys::kKeyDevice).toString();
+ obj.insert("device-path", dev);
+
+ QString srcDev = findEncryptSrcDev(params.value(encrypt_param_keys::kKeyPrefferDevice).toString());
+ obj.insert("device", srcDev);
+ qInfo() << "found source device:" << srcDev;
+
+ QJsonDocument doc(obj);
+
+ QFile f(QString("%1/decrypt.json").arg(kBootUsecPath));
+ if (f.exists())
+ qWarning() << "the decrypt task will be replaced";
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qWarning() << "cannot open decrypt file for writing";
+ return -kErrorOpenFileFailed;
+ }
+
+ f.write(doc.toJson());
+ f.close();
+ return kSuccess;
+}
+
+QString DecryptWorker::findEncryptSrcDev(const QString &activeName)
+{
+ QFile f("/etc/crypttab");
+ if (!f.open(QIODevice::ReadOnly)) {
+ qWarning() << "cannot open crypttab!";
+ return "";
+ }
+ QByteArray contents = f.readAll();
+ f.close();
+ QByteArrayList lines = contents.split('\n');
+ for (auto line : lines) {
+ auto items = QString(line).split(QRegularExpression(R"( |\t)"), QString::SkipEmptyParts);
+ if (items.count() != 4)
+ continue;
+ if (items.at(0) == activeName)
+ return items.at(1);
+ }
+ return "";
+}
+
+ChgPassWorker::ChgPassWorker(const QString &jobID, const QVariantMap ¶ms, QObject *parent)
+ : Worker(jobID, parent),
+ params(params)
+{
+}
+
+void ChgPassWorker::run()
+{
+ QString dev = params.value(encrypt_param_keys::kKeyDevice).toString();
+ QString oldPass = decryptPasswd(params.value(encrypt_param_keys::kKeyOldPassphrase).toString());
+ QString newPass = decryptPasswd(params.value(encrypt_param_keys::kKeyPassphrase).toString());
+
+ int newSlot = 0;
+ int ret = 0;
+ if (params.value(encrypt_param_keys::kKeyValidateWithRecKey, false).toBool())
+ ret = disk_encrypt_funcs::bcChangePassphraseByRecKey(dev, oldPass, newPass, &newSlot);
+ else
+ ret = disk_encrypt_funcs::bcChangePassphrase(dev, oldPass, newPass, &newSlot);
+
+ QString token = params.value(encrypt_param_keys::kKeyTPMToken).toString();
+ if (!token.isEmpty() && ret == 0) {
+ // The value in keyslots represents the keyslot location where the passphrase is located
+ QJsonDocument doc = QJsonDocument::fromJson(token.toLocal8Bit());
+ QJsonObject obj = doc.object();
+ obj.insert("keyslots", QJsonArray::fromStringList({ QString::number(newSlot) }));
+ doc.setObject(obj);
+ token = doc.toJson(QJsonDocument::Compact);
+
+ ret = disk_encrypt_funcs::bcSetToken(dev, token);
+ if (ret != 0) // update token failed, need to rollback the change.
+ disk_encrypt_funcs::bcChangePassphrase(dev, newPass, oldPass, &newSlot);
+ }
+
+ setExitCode(ret);
+}
+
+ReencryptWorkerV2::ReencryptWorkerV2(QObject *parent)
+ : Worker("", parent)
+{
+}
+
+void ReencryptWorkerV2::setEncryptParams(const QVariantMap ¶ms)
+{
+ QWriteLocker lk(&lockParam);
+ this->params = params;
+}
+
+void ReencryptWorkerV2::loadReencryptConfig(const QString &device)
+{
+ disk_encrypt_utils::bcReadEncryptConfig(&config, device);
+}
+
+EncryptConfig ReencryptWorkerV2::encryptConfig() const
+{
+ return config;
+}
+
+void ReencryptWorkerV2::ignoreParamRequest()
+{
+ QWriteLocker locker(&lockRequest);
+ ignoreRequest = true;
+ qInfo() << "ignore param request.";
+}
+
+void ReencryptWorkerV2::run()
+{
+ auto fd = utils::inhibit(tr("Encrypting..."));
+
+ if (!hasUnfinishedOnlineEncryption()) {
+ qInfo() << "no unfinished encryption job exists. exit thread.";
+ return;
+ }
+
+ QString clearDev;
+ // found unfinished encrypt job, disable recovery.
+ if (config.configPath.endsWith("encrypt.json")) {
+ disableABRecovery();
+ clearDev = config.clearDev;
+ }
+
+ if (waitForInput() == kIgnoreRequest) {
+ setExitCode(-kIgnoreRequest);
+ return;
+ }
+
+ // this open action here is for repairing the reencrypt process.
+ int ret = disk_encrypt_funcs::bcOpenDevice(config.devicePath, config.clearDev);
+ if (ret != kSuccess) {
+ qWarning() << "cannot open device for reencryption!" << ret;
+ Q_EMIT deviceReencryptResult(config.devicePath, ret, "");
+ return;
+ }
+
+ if (config.isDetachedHeader) {
+ if (!setFsPassno(config.clearDevUUID, "0")) {
+ qCritical() << "set filesystem passno to 0 failed, uuid is " << config.clearDevUUID;
+ Q_EMIT deviceReencryptResult(config.devicePath, -kErrorSetFsPassno, "");
+ return;
+ }
+ }
+ QString msg;
+ ret = disk_encrypt_funcs::bcResumeReencrypt(config.devicePath, "", clearDev, false);
+ if (ret == kSuccess) {
+ // sets the passphrase, token, recovery-key
+ setPassphrase();
+ if (config.isDetachedHeader) {
+ if (!setFsPassno(config.clearDevUUID, "2")) {
+ qWarning() << "set filesystem passno to 2 failed, uuid is " << config.clearDevUUID;
+ }
+ }
+ setBakcingDevLabel();
+ updateCrypttab();
+ removeEncryptFile();
+ QString recKey;
+ bool expKey;
+ setRecoveryKey(&recKey, &expKey);
+ if (expKey && !recKey.isEmpty()) {
+ if (!disk_encrypt_utils::bcSaveRecoveryKey(config.devicePath,
+ recKey,
+ params.value(encrypt_param_keys::kKeyRecoveryExportPath).toString())) {
+ ret = -KErrorRequestExportRecKey;
+ msg = recKey;
+ }
+ }
+ } else {
+ setExitCode(ret);
+ }
+ Q_EMIT deviceReencryptResult(config.devicePath, ret, msg);
+}
+
+bool ReencryptWorkerV2::hasUnfinishedOnlineEncryption()
+{
+ if (config.devicePath.isEmpty()) {
+ qInfo() << "no unfinished encrypt device.";
+ return false;
+ }
+
+ // 2. check if it's really unfinished.
+ EncryptStates status;
+ if (kSuccess != block_device_utils::bcDevEncryptStatus(config.devicePath, &status)) {
+ qWarning() << "cannot get encrypt requirements!" << config.devicePath;
+ return false;
+ }
+
+ if ((status & kStatusOnline)
+ && (status & kStatusEncrypt)) {
+ // 3. start a worker if device is not finished ONLINE encryption.
+ qInfo() << "device is not finished ONLINE encryption:" << config.devicePath;
+ return true;
+ }
+ return false;
+}
+
+void ReencryptWorkerV2::setPassphrase()
+{
+ const QString &pass = decryptPasswd(params.value(encrypt_param_keys::kKeyPassphrase).toString());
+ const QString &token = params.value(encrypt_param_keys::kKeyTPMToken).toString();
+ int passKeyslot = -1;
+ int ret = disk_encrypt_funcs::bcChangePassphrase(config.devicePath, "", pass, &passKeyslot);
+ if (ret != kSuccess) {
+ qCritical() << "cannot set passphrase for device!" << config.devicePath << ret;
+ setExitCode(ret);
+ return;
+ }
+
+ if (!token.isEmpty()) {
+ // update token keyslot.
+ auto _token = updateTokenKeyslots(token, passKeyslot);
+ ret = disk_encrypt_funcs::bcSetToken(config.devicePath, _token);
+ if (ret != kSuccess) {
+ qCritical() << "cannot set token for device!" << config.devicePath << ret;
+ setExitCode(ret);
+ return;
+ }
+ }
+
+ qInfo() << "passphrase has been setted at keyslot:" << passKeyslot;
+}
+
+void ReencryptWorkerV2::setRecoveryKey(QString *key, bool *expKey)
+{
+ Q_ASSERT(key && expKey);
+ *expKey = false;
+ const QString &recPath = params.value(encrypt_param_keys::kKeyRecoveryExportPath).toString();
+ if (recPath.isEmpty())
+ return;
+
+ *key = disk_encrypt_utils::bcGenRecKey();
+ if (key->isEmpty()) {
+ qWarning() << "generate recovery key failed!";
+ return;
+ }
+
+ int recKeySlot = -1;
+ const QString &pass = decryptPasswd(params.value(encrypt_param_keys::kKeyPassphrase).toString());
+ int ret = disk_encrypt_funcs::bcChangePassphraseByRecKey(config.devicePath, pass, *key, &recKeySlot);
+ if (ret != kSuccess) {
+ qCritical() << "cannot set recovery key for device!" << config.devicePath << ret;
+ setExitCode(ret);
+ return;
+ }
+ *expKey = true;
+
+ QString recToken = QString("{ 'type': 'usec-recoverykey', 'keyslots': ['%1'] }").arg(recKeySlot);
+ ret = disk_encrypt_funcs::bcSetToken(config.devicePath, recToken);
+ if (ret != kSuccess) {
+ qCritical() << "cannot set recovery token for device!" << config.devicePath << ret;
+ setExitCode(ret);
+ return;
+ }
+ qInfo() << "recovery key has been setted at keyslot:" << recKeySlot;
+}
+
+void ReencryptWorkerV2::setBakcingDevLabel()
+{
+ int ret = disk_encrypt_funcs::bcSetLabel(config.devicePath, config.deviceName);
+ if (ret != kSuccess)
+ qWarning() << "set label to device failed:" << config.devicePath << config.deviceName << ret;
+ qInfo() << "device name setted." << config.devicePath << config.deviceName;
+}
+
+void ReencryptWorkerV2::updateCrypttab()
+{
+ qInfo() << "start updating crypttab...";
+
+ QString tpmToken = params.value(encrypt_param_keys::kKeyTPMToken).toString();
+ if (tpmToken.isEmpty())
+ return;
+
+ // do update crypttab item, append tpm info: tpm2-device=auto
+ QFile crypttab("/etc/crypttab");
+ if (!crypttab.open(QIODevice::ReadOnly)) {
+ qWarning() << "cannot open crypttab for reading";
+ return;
+ }
+ auto contents = crypttab.readAll();
+ crypttab.close();
+
+ bool crypttabUpdated = false;
+ QByteArrayList lines = contents.split('\n');
+ for (auto &line : lines) {
+ QString _line = line;
+ if (_line.contains(config.clearDev)) {
+ if (!_line.contains("tpm2-device=auto")) {
+ _line.append(",tpm2-device=auto");
+ line = _line.toLocal8Bit();
+ crypttabUpdated = true;
+ }
+ break;
+ }
+ }
+ if (!crypttabUpdated) {
+ qInfo() << "no need to update crypttab.";
+ return;
+ }
+
+ contents = lines.join('\n');
+
+ if (!crypttab.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ qWarning() << "cannot open crypttab for writing";
+ return;
+ }
+ crypttab.write(contents.data());
+ crypttab.close();
+ qInfo() << "crypttab has been updated:\n"
+ << contents;
+}
+
+void ReencryptWorkerV2::removeEncryptFile()
+{
+ int ret = ::remove(config.configPath.toStdString().c_str());
+ qInfo() << "encrypt job file has been removed." << ret
+ << config.configPath;
+}
+
+QString ReencryptWorkerV2::updateTokenKeyslots(const QString &token, int keyslot)
+{
+ QJsonDocument doc = QJsonDocument::fromJson(token.toLocal8Bit());
+ auto obj = doc.object();
+ obj.insert("keyslots", QJsonArray::fromStringList({ QString::number(keyslot) }));
+ doc.setObject(obj);
+ return doc.toJson(QJsonDocument::Compact);
+}
+
+bool ReencryptWorkerV2::validateParams()
+{
+ if (params.isEmpty())
+ return false;
+
+ if (params.value(encrypt_param_keys::kKeyDevice).toString() != config.devicePath)
+ return false;
+
+ if (params.value(encrypt_param_keys::kKeyPassphrase).toString().isEmpty())
+ return false;
+
+ return true;
+}
+
+void ReencryptWorkerV2::disableABRecovery()
+{
+ QFile cfg("/etc/default/grub.d/13_deepin_ab_recovery.cfg");
+ QByteArray cfgContents;
+ if (cfg.exists()) {
+ if (!cfg.open(QIODevice::ReadOnly)) {
+ qWarning() << "cannot open recovery config!";
+ return;
+ }
+ cfgContents = cfg.readAll();
+ cfg.close();
+ }
+
+ QByteArrayList lines = cfgContents.split('\n');
+ for (int i = 0; i < lines.count(); ++i) {
+ QString line = lines.at(i);
+ if (line.startsWith("#"))
+ continue;
+
+ if (line.contains("DISABLE_AB_ROLLBACK")) {
+ if (line.contains("export DISABLE_AB_ROLLBACK=true")) {
+ qInfo() << "rollback already disabled.";
+ return;
+ }
+
+ lines.removeAt(i);
+ break;
+ }
+ }
+ lines.append("export DISABLE_AB_ROLLBACK=true\n");
+ cfgContents = lines.join('\n');
+
+ qDebug() << "the ab recovery contents:\n"
+ << cfgContents;
+
+ if (!cfg.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
+ qWarning() << "cannot open recovery config to write!";
+ return;
+ }
+ cfg.write(cfgContents);
+ cfg.close();
+
+ // update grub
+ auto fd = utils::inhibit(QObject::tr("Updating grub..."));
+ qInfo() << "blocking reboot:" << fd.value().fileDescriptor();
+ QTime t;
+ t.start();
+ int ret = system("update-grub");
+ qInfo() << "update grub costs" << t.elapsed() << "ms and result is" << ret;
+}
+
+int ReencryptWorkerV2::waitForInput()
+{
+ while (true) {
+ {
+ QReadLocker lk(&lockParam);
+ if (validateParams())
+ break;
+ }
+ {
+ QReadLocker lk(&lockRequest);
+ if (ignoreRequest)
+ return kIgnoreRequest;
+ }
+
+ Q_EMIT requestEncryptParams(config.keyConfig());
+ QThread::sleep(3); // don't request frequently.
+ }
+ return kSuccess;
+}
+
+bool ReencryptWorkerV2::setFsPassno(const QString &uuid, const QString &state)
+{
+ static const QString kFstabPath { "/etc/fstab" };
+ QFile fstab(kFstabPath);
+ if (!fstab.open(QIODevice::ReadOnly))
+ return false;
+
+ QByteArray fstabContents = fstab.readAll();
+ fstab.close();
+
+ QString devUUID = QString("UUID=%1").arg(uuid);
+ QByteArrayList fstabLines = fstabContents.split('\n');
+ QList fstabItems;
+ bool foundItem = false;
+ int size = fstabLines.size();
+ for (int i = 0; i < size; ++i) {
+ QStringList items;
+ const QString &line = QString::fromUtf8(fstabLines.at(i));
+ if (line.startsWith("#")) {
+ items << line;
+ } else {
+ items = line.split(QRegularExpression(R"(\t| )"), QString::SkipEmptyParts);
+ if (items.count() == 6 && items[0] == devUUID && !foundItem) {
+ items[5] = state;
+ foundItem = true;
+ }
+ }
+ fstabItems.append(items);
+ }
+
+ if (foundItem) {
+ QByteArray newContents;
+ size = fstabItems.size();
+ for (int i = 0; i < size; ++i) {
+ newContents += fstabItems.at(i).join('\t');
+ newContents.append('\n');
+ }
+
+ if (!fstab.open(QIODevice::Truncate | QIODevice::ReadWrite))
+ return false;
+
+ fstab.write(newContents);
+ fstab.flush();
+ fstab.close();
+
+ qDebug() << "old fstab contents:"
+ << fstabContents;
+ qDebug() << "new fstab contents"
+ << newContents;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+QString Worker::decryptPasswd(const QString &passwd)
+{
+ QByteArray encodedByteArray = passwd.toUtf8();
+ QByteArray decodedByteArray = QByteArray::fromBase64(encodedByteArray);
+ return QString::fromUtf8(decodedByteArray);
+}
diff --git a/src/services/diskencrypt/encrypt/encryptworker.h b/src/services/diskencrypt/encrypt/encryptworker.h
new file mode 100644
index 0000000000..7263173b43
--- /dev/null
+++ b/src/services/diskencrypt/encrypt/encryptworker.h
@@ -0,0 +1,140 @@
+// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+#ifndef ENCRYPTWORKER_H
+#define ENCRYPTWORKER_H
+
+#include "diskencrypt_global.h"
+
+#include