|
23 | 23 | #include <unistd.h> |
24 | 24 | #include <fcntl.h> |
25 | 25 | #include <functional> |
| 26 | +#include <stdio.h> |
26 | 27 |
|
27 | 28 | FILE_ENCRYPT_USE_NS |
28 | 29 | using namespace disk_encrypt; |
@@ -355,72 +356,27 @@ int disk_encrypt_funcs::bcDecryptDevice(const QString &device, |
355 | 356 | const QString &passphrase) |
356 | 357 | { |
357 | 358 | // backup header first |
358 | | - QString headerPath; |
359 | | - uint32_t flags; |
360 | | - struct crypt_device *cdev = nullptr; |
361 | 359 | dfmbase::FinallyUtil finalClear([&] { |
362 | | - if (cdev) crypt_free(cdev); |
363 | 360 | gCurrDecryptintDevice.clear(); |
364 | 361 | }); |
365 | 362 | gCurrDecryptintDevice = device; |
366 | 363 |
|
| 364 | + QString headerPath; |
367 | 365 | int ret = bcBackupCryptHeader(device, headerPath); |
368 | 366 | CHECK_INT(ret, "backup header failed " + device, -kErrorBackupHeader); |
369 | 367 |
|
370 | | - ret = crypt_init_data_device(&cdev, |
371 | | - headerPath.toStdString().c_str(), |
372 | | - device.toStdString().c_str()); |
373 | | - CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt); |
374 | | - |
375 | | - ret = crypt_load(cdev, CRYPT_LUKS, nullptr); |
376 | | - CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt); |
377 | | - |
378 | | - ret = crypt_persistent_flags_get(cdev, |
379 | | - CRYPT_FLAGS_REQUIREMENTS, |
380 | | - &flags); |
381 | | - CHECK_INT(ret, "get device flag failed " + device, -kErrorGetReencryptFlag); |
382 | | - bool underEncrypting = (flags & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT) || (flags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT); |
383 | | - |
384 | | - crypt_params_reencrypt param; |
385 | | - ret = crypt_reencrypt_status(cdev, ¶m); |
386 | | - CHECK_INT(ret, "check reencrypt status failed" + device, -kErrorCheckReencryptStatus); |
387 | | - |
388 | | - underEncrypting &= (param.mode == CRYPT_REENCRYPT_ENCRYPT); |
389 | | - CHECK_BOOL(!underEncrypting, |
390 | | - "device is under encrypting... " + device + " the flags are: " + QString::number(flags), |
391 | | - -kErrorWrongFlags); |
392 | | - |
393 | | - if (ret == CRYPT_REENCRYPT_CRASH) { // repair is needed. |
394 | | - QString dmName = "dm-" + device.mid(5); |
395 | | - ret = crypt_activate_by_passphrase(cdev, dmName.toStdString().c_str(), |
396 | | - CRYPT_ANY_SLOT, |
397 | | - passphrase.toStdString().c_str(), |
398 | | - passphrase.length(), |
399 | | - CRYPT_ACTIVATE_RECOVERY); |
400 | | - CHECK_INT(ret, "open device failed " + device, -kErrorActive); |
401 | | - |
402 | | - // close device avoid operating. |
403 | | - ret = crypt_deactivate(cdev, dmName.toStdString().c_str()); |
| 368 | + int status = bcReadHeader(headerPath); |
| 369 | + if (status != kDecryptFully) { |
| 370 | + ret = bcDoDecryptDevice(device, passphrase, headerPath); |
| 371 | + CHECK_INT(ret, "decrypt failed " + device, -kErrorDecryptFailed); |
404 | 372 | } |
405 | 373 |
|
406 | | - ret = crypt_reencrypt_init_by_passphrase(cdev, |
407 | | - nullptr, |
408 | | - passphrase.toStdString().c_str(), |
409 | | - passphrase.length(), |
410 | | - CRYPT_ANY_SLOT, |
411 | | - CRYPT_ANY_SLOT, |
412 | | - nullptr, |
413 | | - nullptr, |
414 | | - decryptParams()); |
415 | | - CHECK_INT(ret, "init reencrypt failed " + device, -kErrorWrongPassphrase); |
416 | | - |
417 | | - ret = crypt_reencrypt(cdev, bcDecryptProgress); |
418 | | - CHECK_INT(ret, "decrypt failed" + device, -kErrorReencryptFailed); |
419 | | - |
420 | | - bool res = fs_resize::recoverySuperblock_ext(device, headerPath); |
| 374 | + bool res = block_device_utils::bcMoveFsForward(device); |
421 | 375 | CHECK_BOOL(res, "recovery fs failed " + device, -kErrorResizeFs); |
422 | 376 |
|
423 | | - if (!headerPath.isEmpty()) ::remove(headerPath.toStdString().c_str()); |
| 377 | + if (!headerPath.isEmpty()) |
| 378 | + ::remove(headerPath.toStdString().c_str()); |
| 379 | + |
424 | 380 | return 0; |
425 | 381 | } |
426 | 382 |
|
@@ -916,3 +872,247 @@ bool disk_encrypt_utils::bcHasEncryptConfig(const QString &dev) |
916 | 872 | const QString &devPath = obj.value("device-path").toString(); |
917 | 873 | return devPath == dev; |
918 | 874 | } |
| 875 | + |
| 876 | +quint64 block_device_utils::bcGetBlockSize(const QString &device) |
| 877 | +{ |
| 878 | + auto dev = bcCreateBlkDev(device); |
| 879 | + if (!dev) |
| 880 | + return 0; |
| 881 | + return dev->getProperty(dfmmount::Property::kPartitionSize).toULongLong(); |
| 882 | +} |
| 883 | + |
| 884 | +bool block_device_utils::bcMoveFsForward(const QString &device) |
| 885 | +{ |
| 886 | + static const quint64 kStepSize = 16 * 1024 * 1024; // luks header size. |
| 887 | + |
| 888 | + QString dev(device); |
| 889 | + QString logFilePath("/boot/usec-crypt/dfm_mv_fs_" + dev.replace("/", "_")); |
| 890 | + |
| 891 | + QFile logFile(logFilePath); |
| 892 | + QFile blockFile(device); |
| 893 | + char *buf = new char[kStepSize]; |
| 894 | + |
| 895 | + auto clearMem = [&] { |
| 896 | + if (logFile.isOpen()) |
| 897 | + logFile.close(); |
| 898 | + if (blockFile.isOpen()) |
| 899 | + blockFile.close(); |
| 900 | + delete[] buf; |
| 901 | + }; |
| 902 | + |
| 903 | + if (!logFile.exists()) { |
| 904 | + if (!logFile.open(QIODevice::Truncate | QIODevice::ReadWrite)) { |
| 905 | + qWarning() << "cannot create log file!" << logFilePath; |
| 906 | + clearMem(); |
| 907 | + return false; |
| 908 | + } |
| 909 | + logFile.close(); |
| 910 | + } |
| 911 | + if (!logFile.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) { |
| 912 | + qWarning() << "cannot open log file!" << logFilePath; |
| 913 | + clearMem(); |
| 914 | + return false; |
| 915 | + } |
| 916 | + |
| 917 | + if (!blockFile.open(QIODevice::ReadWrite | QIODevice::Unbuffered)) { |
| 918 | + qWarning() << "cannot open device!" << device; |
| 919 | + clearMem(); |
| 920 | + return false; |
| 921 | + } |
| 922 | + |
| 923 | + // calc total move counts. |
| 924 | + quint64 partSize = block_device_utils::bcGetBlockSize(device); |
| 925 | + if (partSize == 0) { |
| 926 | + qWarning() << "get block size failed!"; |
| 927 | + clearMem(); |
| 928 | + return false; |
| 929 | + } |
| 930 | + quint64 mvCount = partSize / kStepSize; |
| 931 | + if (partSize % kStepSize) mvCount += 1; |
| 932 | + |
| 933 | + // read break point. |
| 934 | + auto records = logFile.readAll().split(','); |
| 935 | + quint64 lastMovedIndex = (records.count() > 0) ? records.last().toULongLong() : 0; |
| 936 | + |
| 937 | + // start move segments |
| 938 | + disk_encrypt_funcs::bcDecryptProgress(100, 99, nullptr); |
| 939 | + qApp->processEvents(); |
| 940 | + |
| 941 | + quint64 currMovedIndex = lastMovedIndex + 1; |
| 942 | + for (; currMovedIndex <= mvCount; ++currMovedIndex, ++lastMovedIndex) { |
| 943 | + // qInfo() << "moving..." << currMovedIndex << device; |
| 944 | + // seek current move position |
| 945 | + if (!blockFile.seek(currMovedIndex * kStepSize)) { |
| 946 | + qWarning() << "seek pos failed!" << currMovedIndex * kStepSize; |
| 947 | + clearMem(); |
| 948 | + return false; |
| 949 | + } |
| 950 | + |
| 951 | + // read next step |
| 952 | + memset(buf, 0, kStepSize); |
| 953 | + quint64 readed = blockFile.read(buf, kStepSize); |
| 954 | + |
| 955 | + // write to previous step position. |
| 956 | + if (!blockFile.seek((lastMovedIndex)*kStepSize)) { |
| 957 | + qWarning() << "seek target failed!" << lastMovedIndex * kStepSize; |
| 958 | + clearMem(); |
| 959 | + return false; |
| 960 | + } |
| 961 | + quint64 wrote = blockFile.write(buf, readed); |
| 962 | + if (wrote != readed) { |
| 963 | + qWarning() << "read write size not match!"; |
| 964 | + clearMem(); |
| 965 | + return false; |
| 966 | + } |
| 967 | + if (!blockFile.flush() || fsync(blockFile.handle()) != 0) { |
| 968 | + qWarning() << "cannot flush device file!" << device; |
| 969 | + clearMem(); |
| 970 | + return false; |
| 971 | + } |
| 972 | + |
| 973 | + // recore current index. |
| 974 | + QString pos = "," + QString::number(currMovedIndex); |
| 975 | + logFile.write(pos.toLocal8Bit()); |
| 976 | + if (!logFile.flush() || fsync(logFile.handle()) != 0) { |
| 977 | + qWarning() << "cannot flush log file!" << logFilePath; |
| 978 | + clearMem(); |
| 979 | + return false; |
| 980 | + } |
| 981 | + // qInfo() << "moved..." << currMovedIndex << device; |
| 982 | + } |
| 983 | + |
| 984 | + clearMem(); |
| 985 | + |
| 986 | + // remove log file on success. |
| 987 | + ::remove(logFilePath.toStdString().c_str()); |
| 988 | + |
| 989 | + // update udev on move finished. |
| 990 | + ::system("udevadm trigger"); |
| 991 | + |
| 992 | + return true; |
| 993 | +} |
| 994 | + |
| 995 | +int disk_encrypt_funcs::bcDoDecryptDevice(const QString &device, const QString &passphrase, const QString &headerPath) |
| 996 | +{ |
| 997 | + struct crypt_device *cdev = nullptr; |
| 998 | + dfmbase::FinallyUtil finalClear([&] { |
| 999 | + if (cdev) crypt_free(cdev); |
| 1000 | + }); |
| 1001 | + |
| 1002 | + int ret = crypt_init_data_device(&cdev, |
| 1003 | + headerPath.toStdString().c_str(), |
| 1004 | + device.toStdString().c_str()); |
| 1005 | + CHECK_INT(ret, "init device failed " + device, -kErrorInitCrypt); |
| 1006 | + |
| 1007 | + ret = crypt_load(cdev, CRYPT_LUKS, nullptr); |
| 1008 | + CHECK_INT(ret, "load device failed " + device, -kErrorLoadCrypt); |
| 1009 | + |
| 1010 | + uint32_t flags; |
| 1011 | + ret = crypt_persistent_flags_get(cdev, |
| 1012 | + CRYPT_FLAGS_REQUIREMENTS, |
| 1013 | + &flags); |
| 1014 | + CHECK_INT(ret, "get device flag failed " + device, -kErrorGetReencryptFlag); |
| 1015 | + bool underEncrypting = (flags & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT) || (flags & CRYPT_REQUIREMENT_ONLINE_REENCRYPT); |
| 1016 | + |
| 1017 | + crypt_params_reencrypt param; |
| 1018 | + ret = crypt_reencrypt_status(cdev, ¶m); |
| 1019 | + CHECK_INT(ret, "check reencrypt status failed" + device, -kErrorCheckReencryptStatus); |
| 1020 | + |
| 1021 | + underEncrypting &= (param.mode == CRYPT_REENCRYPT_ENCRYPT); |
| 1022 | + CHECK_BOOL(!underEncrypting, |
| 1023 | + "device is under encrypting... " + device + " the flags are: " + QString::number(flags), |
| 1024 | + -kErrorWrongFlags); |
| 1025 | + |
| 1026 | + if (ret == CRYPT_REENCRYPT_CRASH) { // repair is needed. |
| 1027 | + QString dmName = "dm-" + device.mid(5); |
| 1028 | + ret = crypt_activate_by_passphrase(cdev, dmName.toStdString().c_str(), |
| 1029 | + CRYPT_ANY_SLOT, |
| 1030 | + passphrase.toStdString().c_str(), |
| 1031 | + passphrase.length(), |
| 1032 | + CRYPT_ACTIVATE_RECOVERY); |
| 1033 | + CHECK_INT(ret, "open device failed " + device, -kErrorActive); |
| 1034 | + |
| 1035 | + // close device avoid operating. |
| 1036 | + ret = crypt_deactivate(cdev, dmName.toStdString().c_str()); |
| 1037 | + } |
| 1038 | + |
| 1039 | + // if fully decrypted |
| 1040 | + |
| 1041 | + ret = crypt_reencrypt_init_by_passphrase(cdev, |
| 1042 | + nullptr, |
| 1043 | + passphrase.toStdString().c_str(), |
| 1044 | + passphrase.length(), |
| 1045 | + CRYPT_ANY_SLOT, |
| 1046 | + CRYPT_ANY_SLOT, |
| 1047 | + nullptr, |
| 1048 | + nullptr, |
| 1049 | + decryptParams()); |
| 1050 | + CHECK_INT(ret, "init reencrypt failed " + device, -kErrorWrongPassphrase); |
| 1051 | + |
| 1052 | + ret = crypt_reencrypt(cdev, bcDecryptProgress); |
| 1053 | + CHECK_INT(ret, "decrypt failed" + device, -kErrorReencryptFailed); |
| 1054 | + |
| 1055 | + return kSuccess; |
| 1056 | +} |
| 1057 | + |
| 1058 | +int disk_encrypt_funcs::bcReadHeader(const QString &header) |
| 1059 | +{ |
| 1060 | + QFile headerFile(header); |
| 1061 | + if (!headerFile.open(QIODevice::ReadOnly)) { |
| 1062 | + qWarning() << "open header failed!"; |
| 1063 | + return kInvalidHeader; |
| 1064 | + } |
| 1065 | + |
| 1066 | + headerFile.seek(4096); // header json starts at 4096 |
| 1067 | + QString jsonStr = headerFile.readLine(); |
| 1068 | + headerFile.close(); |
| 1069 | + |
| 1070 | + QJsonDocument doc = QJsonDocument::fromJson(jsonStr.toLocal8Bit()); |
| 1071 | + auto obj = doc.object(); |
| 1072 | + |
| 1073 | + // read segments |
| 1074 | + auto segments = obj.value("segments").toObject(); |
| 1075 | + if (segments.isEmpty()) { |
| 1076 | + qWarning() << "segments not found"; |
| 1077 | + return kInvalidHeader; |
| 1078 | + } |
| 1079 | + bool hasLinear = false, hasCrypt = false; |
| 1080 | + for (auto iter = segments.begin(); iter != segments.end(); ++iter) { |
| 1081 | + auto segment = iter.value().toObject(); |
| 1082 | + auto type = segment.value("type").toString(); |
| 1083 | + if (type == "linear") |
| 1084 | + hasLinear = true; |
| 1085 | + if (type == "crypt") |
| 1086 | + hasCrypt = true; |
| 1087 | + } |
| 1088 | + |
| 1089 | + // read mode |
| 1090 | + QString mode; |
| 1091 | + auto keyslots = obj.value("keyslots").toObject(); |
| 1092 | + for (auto iter = keyslots.begin(); iter != keyslots.end(); ++iter) { |
| 1093 | + auto keyslot = iter.value().toObject(); |
| 1094 | + if (keyslot.value("type").toString() == "reencrypt") { |
| 1095 | + mode = keyslot.value("mode").toString(); |
| 1096 | + break; |
| 1097 | + } |
| 1098 | + } |
| 1099 | + |
| 1100 | + if (mode == "encrypt") { |
| 1101 | + if (hasLinear && hasCrypt) |
| 1102 | + return kEncryptInProgress; |
| 1103 | + if (hasLinear) |
| 1104 | + return kEncryptInit; |
| 1105 | + } else if (mode == "decrypt") { |
| 1106 | + if (hasLinear && hasCrypt) |
| 1107 | + return kDecryptInProgress; |
| 1108 | + if (hasCrypt) |
| 1109 | + return kDecryptInit; |
| 1110 | + } else { |
| 1111 | + if (hasLinear && !hasCrypt) |
| 1112 | + return kDecryptFully; |
| 1113 | + if (!hasLinear && hasCrypt) |
| 1114 | + return kEncryptFully; |
| 1115 | + } |
| 1116 | + |
| 1117 | + return kInvalidHeader; |
| 1118 | +} |
0 commit comments