int erase(const std::string& name);
int clean(const std::string& name);
-private:
- int fileErase(const std::string& name);
- int directoryErase(const std::string& name);
- void dropCachePage();
private:
ODEControlContext& context;
- std::string devicePath;
};
} // namespace ode
kernel-keyring.cpp
internal-encryption.cpp
external-encryption.cpp
- engine/ext4-engine.cpp
- engine/dmcrypt-engine.cpp
- engine/ecryptfs-engine.cpp
+ engine/encryption/ext4-engine.cpp
+ engine/encryption/dmcrypt-engine.cpp
+ engine/encryption/ecryptfs-engine.cpp
+ engine/erase/mmc-engine.cpp
key-manager/key-store.cpp
key-manager/key-manager.cpp
key-manager/key-generator.cpp
+++ /dev/null
-/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-#include <linux/dm-ioctl.h>
-#include <sys/mount.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <klay/audit/logger.h>
-
-#include <klay/error.h>
-#include <klay/exception.h>
-#include <klay/filesystem.h>
-
-#include "../file-footer.h"
-#include "../ext4-tool.h"
-
-#include "dmcrypt-engine.h"
-
-#define OPTION_INCLUDE_UNUSED_REGION (1 << 0)
-
-namespace ode {
-
-void CryptInfo::init(const std::string &src, const std::string &crypto_name)
-{
- crypto_type_name = crypto_name;
- fs_size = getBlkdevSize(src);
-}
-
-long CryptInfo::getFileSystemSize()
-{
- return fs_size;
-}
-
-std::string CryptInfo::getCryptoTypeName() const
-{
- return crypto_type_name;
-}
-
-long CryptInfo::getBlkdevSize(const std::string &src)
-{
- int fd = open(src.c_str(), O_RDONLY);
- if (fd < 0)
- return 0;
-
- long fs_size = 0;
- if ((ioctl(fd, BLKGETSIZE, &fs_size)) == -1)
- fs_size = 0;
- close(fd);
-
- return fs_size;
-}
-
-
-static void convertKeyToHexASCII(const DMCryptEngine::data &key,
- DMCryptEngine::data &key_ascii)
-{
- unsigned int i, a;
- unsigned char nibble;
-
- for (i = 0, a = 0; i < key.size(); i++, a += 2) {
- // For each byte, write out two ascii hex digits
- nibble = (key[i] >> 4) & 0xf;
- key_ascii[a] = nibble + (nibble > 9 ? 0x37 : 0x30);
-
- nibble = key[i] & 0xf;
- key_ascii[a + 1] = nibble + (nibble > 9 ? 0x37 : 0x30);
- }
-
- // Add the null termination
- key_ascii[a] = '\0';
-}
-
-DMCryptEngine::DMCryptEngine(const std::string &src, const std::string &dest, const ProgressBar &prgsBar) :
- source(src), destination(dest), progressBar(prgsBar)
-{
- // 1. Get Real Block device(src)'s infomation
- cryptInfo.init(src, "aes-cbc-essiv:sha256");
-}
-
-DMCryptEngine::~DMCryptEngine()
-{
-}
-
-static void ioctlInit(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
-{
- memset(io, 0, dataSize);
- io->data_size = dataSize;
- io->data_start = sizeof(struct dm_ioctl);
- io->version[0] = 4;
- io->version[1] = 0;
- io->version[2] = 0;
- io->flags = flags;
- if (name) {
- memset(io->name, 0, sizeof(io->name));
- strncpy(io->name, name, sizeof(io->name) - 1);
- }
-}
-
-#define DM_CRYPT_BUF_SIZE 4096
-#define DM_LABEL "userdata"
-
-static const std::string createCryptoBlkDev(const std::string &real_blkdev, const std::string &mount_name, const DMCryptEngine::data &key, long fileSystemSize, std::string cryptoTypeName)
-{
- int fd = -1;
-
- std::string crypto_blkdev;
- ode::DMCryptEngine::data key_ascii(512);
-
- /*
- * dm_buffer |-------------------------------------------------| 4096
- * dm_io |----------| size of dm_ioctl
- * dm_ts |--------------| size of dm_Target_spec
- * crypt_params |---------------------|
- */
- char dm_buffer[DM_CRYPT_BUF_SIZE]; // first: for dm_io, dm_ts
- struct dm_ioctl *dm_io;
- struct dm_target_spec *dm_ts;
- unsigned int dm_minor;
-
- char *crypt_params; // protocol for dm-crypt
-
- // Open dm control IOCTL
- if ((fd = open("/dev/mapper/control", O_RDWR)) < 0)
- throw runtime::Exception("Cannot open device-mapper");
-
- /*
- * dm_buffer |-------------------------------------------------| 4096
- * dm_io |----------| size of dm_ioctl
- */
- dm_io = (struct dm_ioctl *)dm_buffer;
-
- // Clean-up dm_ioctl
- // Create Device (mount_name)
- ioctlInit(dm_io, DM_CRYPT_BUF_SIZE, mount_name.c_str(), 0);
- if (ioctl(fd, DM_DEV_CREATE, dm_io)) {
- close(fd);
- throw runtime::Exception("Cannot create dm-crypt device");
- }
-
- // Clean-up dm_ioctl
- // Get the device status, in particular, the mount_name of it's device file
- ioctlInit(dm_io, DM_CRYPT_BUF_SIZE, mount_name.c_str(), 0);
- if (ioctl(fd, DM_DEV_STATUS, dm_io)) {
- close(fd);
- throw runtime::Exception("Cannot retrieve dm-crypt device status");
- }
-
- // Store created device into crypto_blkdev
- dm_minor = (dm_io->dev & 0xff) | ((dm_io->dev >> 12) & 0xfff00);
- crypto_blkdev = "/dev/dm-" + std::to_string(dm_minor);
-
- // Load the mapping table for this device
- dm_ts = (struct dm_target_spec *)&dm_buffer[sizeof(struct dm_ioctl)];
-
- /*
- * dm_buffer |-------------------------------------------------| 4096
- * dm_io |----------| size of dm_ioctl
- * dm_ts |--------------| size of dm_Target_spec
- */
-
- // Force clean-up whole dm_buffer
- ioctlInit(dm_io, 4096, mount_name.c_str(), 0);
- dm_io->target_count = 1;
- dm_ts->status = 0;
- dm_ts->sector_start = 0;
- dm_ts->length = fileSystemSize;
- strcpy(dm_ts->target_type, "crypt");
-
- // Prepare crypt_params
- /*
- * dm_buffer |-------------------------------------------------| 4096
- * dm_io |----------| size of dm_ioctl
- * dm_ts |--------------| size of dm_Target_spec
- * crypt_params |---------------------|
- */
-
- crypt_params = dm_buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
-
- ode::convertKeyToHexASCII(key, key_ascii);
-
- // Store crypt_params
- sprintf(crypt_params, "%s %s 0 %s 0", cryptoTypeName.c_str(), key_ascii.data(), real_blkdev.c_str());
-
- crypt_params += strlen(crypt_params) + 1;
- // Align to an 8 byte boundary
- crypt_params = (char *)(((unsigned long)crypt_params + 7) & ~8);
- dm_ts->next = crypt_params - dm_buffer;
-
- // Table load
- if (ioctl(fd, DM_TABLE_LOAD, dm_io) < 0) {
- close(fd);
- throw runtime::Exception("Cannot load dm-crypt mapping table.");
- }
-
- // Force clean-up whole dm_buffer
- // Resume this device to activate it
- ioctlInit(dm_io, 4096, mount_name.c_str(), 0);
- if (ioctl(fd, DM_DEV_SUSPEND, dm_io)) {
- close(fd);
- throw runtime::Exception("Cannot resume the dm-crypt device");
- }
-
- // If fd is <0 from a failed open call,
- // it's safe to just ignore the close error
- if (fd >= 0)
- close(fd);
-
- return crypto_blkdev;
-}
-
-static void destroyCryptoBlkDev(const std::string &mount_name)
-{
- int fd;
- char buffer[DM_CRYPT_BUF_SIZE];
- struct dm_ioctl *io;
-
- if ((fd = open("/dev/mapper/control", O_RDWR)) < 0)
- throw runtime::Exception("Cannot open device-mapper");
-
- io = (struct dm_ioctl *)buffer;
-
- ioctlInit(io, DM_CRYPT_BUF_SIZE, mount_name.c_str(), 0);
- if (ioctl(fd, DM_DEV_REMOVE, io)) {
- close(fd);
- throw runtime::Exception("Cannot remove dm-crypt device");
- }
-
- if (fd >= 0)
- close(fd);
-}
-
-#define DMCRYPT_KEY_MIN_LEN_BYTE (32)
-#define DMCRYPT_KEY_MIN_LEN_BIT (DMCRYPT_KEY_MIN_LEN_BYTE*8)
-
-static ode::DMCryptEngine::data sanitizeKey(const ode::DMCryptEngine::data &key)
-{
- if (key.size() < DMCRYPT_KEY_MIN_LEN_BYTE)
- throw runtime::Exception("Key length isn't enough to be used for dmcrypt");
- else if (key.size() > DMCRYPT_KEY_MIN_LEN_BYTE)
- return ode::DMCryptEngine::data(key.begin(), key.begin() + DMCRYPT_KEY_MIN_LEN_BYTE);
- else
- return key;
-}
-
-void DMCryptEngine::mount(const DMCryptEngine::data &key, unsigned int options)
-{
- DMCryptEngine::data sanitized_key = sanitizeKey(key);
-
- // create crypto type device mapping layer to mount the encrypted partition.
- const std::string crypto_blkdev = createCryptoBlkDev(source, DM_LABEL, sanitized_key, cryptInfo.getFileSystemSize(), cryptInfo.getCryptoTypeName());
-
- if (::mount(crypto_blkdev.c_str(), destination.c_str(), "ext4", 0, 0) < 0)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-}
-
-void DMCryptEngine::umount()
-{
- if (::umount(destination.c_str()))
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-
- destroyCryptoBlkDev(DM_LABEL);
-}
-
-void DMCryptEngine::encryptInPlace(const std::string &src_blkdev,
- const std::string &dst_blkdev,
- const bool isFastEncEnabled)
-{
- Ext4Tool ext4tool(src_blkdev);
- ext4tool.forceCleanUp();
-
- const unsigned int SRC_BLOCK_SIZE = ext4tool.getBlockSize();
- const unsigned int SRC_TOTAL_BLOCK_COUNT = ext4tool.getTotalBlockCount();
- char buff[SRC_BLOCK_SIZE] = {0, };
-
- runtime::File dst(dst_blkdev, O_WRONLY);
- runtime::File src(src_blkdev, O_RDONLY);
-
- for (unsigned int n = 0; n < SRC_TOTAL_BLOCK_COUNT; n++) {
- if (isFastEncEnabled && ext4tool.isUsedBlock(n) == false)
- continue;
-
- src.lseek(n * SRC_BLOCK_SIZE, SEEK_SET);
- dst.lseek(n * SRC_BLOCK_SIZE, SEEK_SET);
-
- src.read(buff, SRC_BLOCK_SIZE);
- dst.write(buff, SRC_BLOCK_SIZE);
-
- progressBar.update(n, SRC_TOTAL_BLOCK_COUNT, 1);
- }
- progressBar.done();
-}
-
-void DMCryptEngine::encrypt(const DMCryptEngine::data &key, unsigned int options)
-{
- DMCryptEngine::data sanitized_key = sanitizeKey(key);
-
- // create crypto type device mapping layer to mount the plain partition
- // should be encrypted here.
- const std::string crypto_blkdev = createCryptoBlkDev(source, DM_LABEL, sanitized_key, cryptInfo.getFileSystemSize(), cryptInfo.getCryptoTypeName());
-
- bool isFastEncEnabled = true;
- if (options == OPTION_INCLUDE_UNUSED_REGION)
- isFastEncEnabled = false;
-
- INFO("FastEncryption: " + std::string(isFastEncEnabled ? "Enabled" : "Disabled"));
-
- // We always do In-place encryption
- encryptInPlace(source, crypto_blkdev, isFastEncEnabled);
-
- // remove crypto type device mapper
- destroyCryptoBlkDev(DM_LABEL);
-}
-
-void DMCryptEngine::decrypt(const DMCryptEngine::data &key, unsigned int options)
-{
- DMCryptEngine::data sanitized_key = sanitizeKey(key);
-
- // create crypto type device mapping layer to mount the plain partition
- // should be encrypted here.
- const std::string crypto_blkdev = createCryptoBlkDev(source, DM_LABEL, sanitized_key, cryptInfo.getFileSystemSize(), cryptInfo.getCryptoTypeName());
-
- bool isFastEncEnabled = true;
- if (options == OPTION_INCLUDE_UNUSED_REGION)
- isFastEncEnabled = false;
-
- INFO("FastEncryption: " + std::string(isFastEncEnabled ? "Enabled" : "Disabled"));
-
- // We always do In-place encryption
- encryptInPlace(crypto_blkdev, source, isFastEncEnabled);
-
- // remove crypto type device mapper
- destroyCryptoBlkDev(DM_LABEL);
-}
-
-bool DMCryptEngine::isKeyMetaSet()
-{
- return FileFooter::exist(source);
-}
-
-const DMCryptEngine::data DMCryptEngine::getKeyMeta()
-{
- return FileFooter::read(source);
-}
-
-void DMCryptEngine::setKeyMeta(const data &meta)
-{
- FileFooter::write(source, meta);
-}
-
-void DMCryptEngine::clearKeyMeta()
-{
- FileFooter::clear(source);
-}
-
-unsigned int DMCryptEngine::getSupportedOptions()
-{
- return OPTION_INCLUDE_UNUSED_REGION;
-}
-
-} // namespace ode
+++ /dev/null
-/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-#ifndef __DMCRYPT_ENGINE_H__
-#define __DMCRYPT_ENGINE_H__
-
-#include <vector>
-#include <string>
-
-#include "progress-bar.h"
-
-namespace ode {
-
-class CryptInfo {
-public:
- void init(const std::string &src, const std::string &crypto_name);
- long getFileSystemSize();
- std::string getCryptoTypeName() const;
-
-private:
- long getBlkdevSize(const std::string &src);
-
-private:
- // TODO(seok85.hong): support fast-encryption
- long fs_size;
- std::string crypto_type_name;
-};
-
-
-class DMCryptEngine final {
-public:
- DMCryptEngine(const std::string &src, const std::string &dest, const ProgressBar &prgsBar);
- DMCryptEngine(const DMCryptEngine &) = delete;
- DMCryptEngine(DMCryptEngine &&) = delete;
- ~DMCryptEngine();
-
- DMCryptEngine &operator=(const DMCryptEngine &) = delete;
- DMCryptEngine &operator=(DMCryptEngine &&) = delete;
-
- const std::string &getSource()
- {
- return source;
- }
-
- const std::string &getDestination()
- {
- return destination;
- }
-
- typedef std::vector<unsigned char> data;
-
- void mount(const data &key, unsigned int options);
- void umount();
-
- void encrypt(const data &key, unsigned int options);
- void decrypt(const data &key, unsigned int options);
-
- bool isKeyMetaSet();
- const data getKeyMeta();
- void setKeyMeta(const data &data);
- void clearKeyMeta();
-
- unsigned int getSupportedOptions();
-
-private:
- void encryptInPlace(const std::string &src_blkdev,
- const std::string &dst_blkdev,
- const bool isFastEncEnabled);
-
-private:
- std::string source, destination;
- CryptInfo cryptInfo;
- ProgressBar progressBar;
-};
-
-} // namespace ode
-#endif // __DMCRYPT_ENGINE_H__
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-#include <iomanip>
-
-#include <unistd.h>
-#include <sys/vfs.h>
-#include <sys/mount.h>
-
-#include <klay/error.h>
-#include <klay/exception.h>
-#include <klay/filesystem.h>
-#include <klay/audit/logger.h>
-
-#include "../kernel-keyring.h"
-#include "../file-footer.h"
-
-#include "ecryptfs-engine.h"
-
-#define OPTION_ONLY_NEW_FILE (1 << 0)
-#define OPTION_EXCEPT_FOR_MEDIA_FILE (1 << 1)
-
-#define SUPPORTED_OPTIONS OPTION_ONLY_NEW_FILE
-
-#define MEDIA_EXCLUSION_LIST "temp_video/Camera/DCIM:mp3|mpga|m4a|mp4|wav|amr|awb|wma|ogg|oga|aac|mka|flac|3gp|3ga|mid|midi|xmf|rtttl|rtx|ota|smf|spm|imy|mpeg|m4v|3gp|3gpp|3g2|3gpp2|wmv|asf|mkv|webm|ts|avi|jpg|jpeg|gif|png|bmp|wbmp|divx|flv|ac3|mov|tiff|f4v|mpeg3|voice"
-
-#define CIPHER_MODE "aes"
-#define ENCRYPTION_CHECKER_NAME ".ecryptfs_encrypted"
-
-
-#define ECRYPTFS_VERSION_MAJOR 0x00
-#define ECRYPTFS_VERSION_MINOR 0x04
-#define ECRYPTFS_VERSION ((ECRYPTFS_VERSION_MAJOR << 8) | ECRYPTFS_VERSION_MINOR)
-
-#define ECRYPTFS_MAX_KEY_BYTES 64
-#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
-#define ECRYPTFS_SIG_SIZE 8
-#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
-#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
-#define ECRYPTFS_SALT_SIZE 8
-#define ECRYPTFS_MAX_KEY_MOD_NAME_BYTES 16
-
-struct ecryptfs_session_key {
-#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
-#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
-#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
-#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
- int32_t flags;
- int32_t encrypted_key_size;
- int32_t decrypted_key_size;
- uint8_t encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
- uint8_t decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
-};
-
-struct ecryptfs_password {
- int32_t password_bytes;
- int32_t hash_algo;
- int32_t hash_iterations;
- int32_t session_key_encryption_key_bytes;
-#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
-#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
- uint32_t flags;
- uint8_t session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
- uint8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
- uint8_t salt[ECRYPTFS_SALT_SIZE];
-};
-
-struct ecryptfs_private_key {
- uint32_t key_size;
- uint32_t data_len;
- uint8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
- char key_mod_alias[ECRYPTFS_MAX_KEY_MOD_NAME_BYTES + 1];
- uint8_t data[];
-};
-
-enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
-
-struct ecryptfs_auth_tok {
- uint16_t version;
- uint16_t token_type;
-#define ECRYPTFS_ENCRYPT_ONLY 0x00000001
- uint32_t flags;
- struct ecryptfs_session_key session_key;
- uint8_t reserved[32];
- union {
- struct ecryptfs_password password;
- struct ecryptfs_private_key private_key;
- } token;
-} __attribute__((packed));
-
-#if 0
-#define ECRYPTFS_IOCTL_GET_ATTRIBUTES _IOR('l', 0x10, unsigned int)
-#define ECRYPTFS_WAS_ENCRYPTED 0x0080
-#define ECRYPTFS_WAS_ENCRYPTED_OTHER_DEVICE 0x0100
-#endif
-
-#define ECRYPTFS_AUTH_TOKEN_TYPE "user"
-
-namespace ode {
-
-namespace {
-
-unsigned long long getAvailableSpace(const std::string& mountPoint)
-{
- struct statfs statbuf;
- if (::statfs(mountPoint.c_str(), &statbuf)) {
- throw runtime::Exception("Failed to access " + mountPoint);
- }
-
- return (unsigned long long)statbuf.f_bfree * statbuf.f_bsize;
-}
-
-bool wasEncrypted(const std::string &path)
-{
-#ifdef ECRYPTFS_IOCTL_GET_ATTRIBUTES
- unsigned int attrs = 0;
- bool ret = false;
- int fd = 0;
-
- fd = ::open(path.c_str(), O_RDWR);
- if (fd < 0) {
- throw runtime::Exception("Failed to open " + path);
- }
-
- if (::ioctl(fd, ECRYPTFS_IOCTL_GET_ATTRIBUTES, &attrs) == 0 &&
- (attrs & ECRYPTFS_WAS_ENCRYPTED)) {
- ret = true;
- }
- ::close(fd);
-
- return ret;
-#else
- return true;
-#endif
-}
-
-unsigned long long getEncryptedSize(const runtime::File &file) {
- unsigned long long originalSize = file.size();
- unsigned long long result = 0;
-
- if (originalSize % 4096) {
- originalSize = (1 + originalSize / 4096) * 4096;
- }
-
-#ifdef ECRYPTFS_IOCTL_GET_ATTRIBUTES
- if (wasEncrypted(file.getPath())) {
- result = originalSize;
- } else {
-#endif
- result = originalSize + 2 * 4096;
-#ifdef ECRYPTFS_IOCTL_GET_ATTRIBUTES
- }
-#endif
-
- //TODO : block size have to not hard-coded.
- // If there is a better way, the followings have to be changed.
- unsigned int blockSize = 4096;
- if (result % blockSize) {
- result = (1 + result / blockSize) * blockSize;
- }
-
- return result;
-}
-
-unsigned long long getDecryptedSize(const runtime::File &file) {
- unsigned long long originalSize = file.size();
- unsigned long long result = originalSize;
-
- if (wasEncrypted(file.getPath())) {
- if (originalSize > 2 * 4096) {
- result = originalSize - 2 * 4096;
- }
- }
-
- result = originalSize;
-
- //TODO : block size have to not hard-coded.
- // If there is a better way, the followings have to be changed.
- unsigned int blockSize = 4096;
- if (result % blockSize) {
- result = (1 + result / blockSize) * blockSize;
- }
-
- return result;
-}
-
-bool isEnoughToCopyInPlace(const std::string& path,
- const std::function<unsigned long long(const runtime::File&)> getSizeFunc)
-{
- unsigned long long availableSpace = getAvailableSpace(path);
-
- std::function<bool(const std::string &path)> check;
- check = [&check, &getSizeFunc, availableSpace](const std::string &path) {
- for (runtime::DirectoryIterator iter(path), end;
- iter != end; ++iter) {
- if (iter->isDirectory()) {
- if (!check(iter->getPath())) {
- return false;
- }
- } else if (getSizeFunc(*iter) > availableSpace) {
- //TODO : have to consider changing file size
- // when encrypt/decrypt
- return false;
- }
- }
- return true;
- };
-
- return check(path);
-}
-
-void copyInPlace(const std::string& source, const std::string& destination,
- const std::string& temp,
- const std::function<bool(const std::string&)> &isTarget,
- const std::function<void(unsigned long long)> &addProgress)
-{
- for (runtime::DirectoryIterator iter(source), end;
- iter != end; ++iter) {
- if (iter->isDirectory()) {
- copyInPlace(iter->getPath(), destination + "/" + iter->getName(),
- temp, isTarget, addProgress);
- } else if (isTarget(iter->getPath())) {
- std::string tempFilePath = temp + "/" + iter->getName();
- std::string destFilePath = destination + "/" + iter->getName();
-
- iter->copyTo(tempFilePath);
- iter->remove();
- if (::rename(tempFilePath.c_str(), destFilePath.c_str()) != 0) {
- throw runtime::Exception("Failed to rename from " + tempFilePath + " to " + destFilePath);
- }
-
- addProgress(iter->size());
- }
- }
-}
-
-void ecryptfsMount(const std::string &source, const std::string &destination, const std::vector<unsigned char> &key, unsigned int options)
-{
- ecryptfs_auth_tok payload;
- std::string mountOption;
-
- ::memset(&(payload), 0, sizeof(ecryptfs_auth_tok));
-
- payload.version = ECRYPTFS_VERSION;
- payload.token_type = ECRYPTFS_PASSWORD;
- payload.token.password.flags = ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
- payload.token.password.session_key_encryption_key_bytes =
- (ECRYPTFS_MAX_KEY_BYTES > key.size())? key.size() :
- ECRYPTFS_MAX_KEY_BYTES;
- ::memcpy(payload.token.password.session_key_encryption_key, key.data(),
- payload.token.password.session_key_encryption_key_bytes);
-
- std::stringstream signature;
- signature<< std::hex << std::setfill('0') << std::setw(2);
- for (unsigned int byte : key) {
- signature << byte;
- }
- for (int i = key.size(); i < ECRYPTFS_SIG_SIZE; i++) {
- signature << (unsigned int) 0;
- }
- ::memcpy((char *)payload.token.password.signature,
- signature.str().c_str(), ECRYPTFS_PASSWORD_SIG_SIZE);
-
- if (KernelKeyRing::search(KEY_SPEC_USER_KEYRING, ECRYPTFS_AUTH_TOKEN_TYPE,
- (char *)payload.token.password.signature, 0) < 0) {
- if (KernelKeyRing::add(ECRYPTFS_AUTH_TOKEN_TYPE,
- (char *)payload.token.password.signature,
- (void *)&payload, sizeof(payload),
- KEY_SPEC_USER_KEYRING) < 0) {
- throw runtime::Exception("Unable to add token to keyring.");
- }
- }
-
- mountOption = "ecryptfs_passthrough"
- ",ecryptfs_cipher=" CIPHER_MODE
- ",ecryptfs_sig=" + std::string((char *)payload.token.password.signature) +
- ",ecryptfs_key_bytes=" + std::to_string(payload.token.password.session_key_encryption_key_bytes);
-
- if (options & OPTION_EXCEPT_FOR_MEDIA_FILE) {
- mountOption += ",ecryptfs_enable_filtering=" MEDIA_EXCLUSION_LIST;
- }
-
- INFO("option = " + mountOption);
- INFO("source = " + source);
- INFO("dest = " + destination);
-
- if (::mount(source.c_str(), destination.c_str(), "ecryptfs", MS_NODEV,
- mountOption.c_str()) != 0) {
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- }
-}
-
-void ecryptfsUmount(const std::string &destination)
-{
- if (::umount(destination.c_str()) != 0) {
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- }
-
- //TODO : remove key from keyring
-}
-
-} // namespace
-
-EcryptfsEngine::EcryptfsEngine(const std::string &src, const std::string &dest, const ProgressBar &prg) :
- source(src), destination(dest), progress(prg)
-{
-}
-
-EcryptfsEngine::~EcryptfsEngine()
-{
-}
-
-void EcryptfsEngine::mount(const data &key, unsigned int options)
-{
- ecryptfsMount(source, destination, key, options);
-}
-
-void EcryptfsEngine::umount()
-{
- ecryptfsUmount(destination);
-}
-
-void EcryptfsEngine::encrypt(const data &key, unsigned int options)
-{
- if (!isEnoughToCopyInPlace(source, getDecryptedSize)) {
- throw runtime::Exception("No space to encryption");
- }
-
- progress.update(0);
-
- try {
- ecryptfsMount(source, destination, key, options);
- } catch (runtime::Exception &e) {
- throw runtime::Exception("Failed to mount - " + std::string(e.what()));
- }
-
- try {
- unsigned long long totalSize = getAvailableSpace(source), current;
- runtime::File tempDir(destination + "/" ENCRYPTION_CHECKER_NAME);
-
- tempDir.makeDirectory();
- if (!(options & OPTION_ONLY_NEW_FILE)) {
- copyInPlace(destination, destination, tempDir.getPath(),
- [](const std::string &file) {
- return true;
- },
- [¤t, &totalSize, this](unsigned long long size) {
- current += size;
- this->progress.update(current * 100 / totalSize);
- });
- }
- } catch (runtime::Exception &e) {
- try {
- ecryptfsUmount(destination);
- } catch (runtime::Exception &e) {}
- throw runtime::Exception("Failed to encrypt file - " + std::string(e.what()));
- }
-
- sync();
-
- progress.done();
-}
-
-void EcryptfsEngine::decrypt(const data &key, unsigned int options)
-{
- if (!isEnoughToCopyInPlace(destination, getEncryptedSize)) {
- throw runtime::Exception("No space to encryption");
- }
-
- progress.update(0);
-
- try {
- unsigned long long totalSize = getAvailableSpace(source), current;
- runtime::File tempDir(source + "/" ENCRYPTION_CHECKER_NAME);
- runtime::File tempMountpoint(tempDir.getPath() + "/mount");
-
- tempMountpoint.makeDirectory();
- ecryptfsMount(source, tempMountpoint.getPath(), key, 0);
-
- copyInPlace(tempMountpoint.getPath(), source,
- tempDir.getPath(), wasEncrypted,
- [¤t, &totalSize, this](unsigned long long size) {
- current += size;
- this->progress.update(current * 100 / totalSize);
- });
- ecryptfsUmount(tempMountpoint.getPath());
-
- tempDir.remove(true);
- } catch (runtime::Exception &e) {
- throw runtime::Exception("Failed to decrypt file - " + std::string(e.what()));
- }
-
- sync();
-
- progress.done();
-}
-
-bool EcryptfsEngine::isKeyMetaSet()
-{
- return FileFooter::exist(source);
-}
-
-const EcryptfsEngine::data EcryptfsEngine::getKeyMeta()
-{
- return FileFooter::read(source);
-}
-
-void EcryptfsEngine::setKeyMeta(const data &meta)
-{
- FileFooter::write(source, meta);
-}
-
-void EcryptfsEngine::clearKeyMeta()
-{
- FileFooter::clear(source);
-}
-
-unsigned int EcryptfsEngine::getSupportedOptions()
-{
- return SUPPORTED_OPTIONS;
-}
-
-} // namespace ode
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-#ifndef __ECRYPTFS_ENGINE_H__
-#define __ECRYPTFS_ENGINE_H__
-
-#include <vector>
-#include <string>
-
-#include "../progress-bar.h"
-
-namespace ode {
-
-class EcryptfsEngine final {
-public:
- EcryptfsEngine(const std::string& src, const std::string& dest, const ProgressBar& prgs);
- EcryptfsEngine(const EcryptfsEngine&) = delete;
- EcryptfsEngine(EcryptfsEngine&&) = delete;
- ~EcryptfsEngine();
-
- EcryptfsEngine& operator=(const EcryptfsEngine&) = delete;
- EcryptfsEngine& operator=(EcryptfsEngine&&) = delete;
-
- const std::string& getSource()
- {
- return source;
- }
-
- const std::string& getDestination()
- {
- return destination;
- }
-
- typedef std::vector<unsigned char> data;
-
- void mount(const data& key, unsigned int);
- void umount();
-
- void encrypt(const data& key, unsigned int);
- void decrypt(const data& key, unsigned int);
-
- bool isKeyMetaSet();
- const data getKeyMeta();
- void setKeyMeta(const data &data);
- void clearKeyMeta();
-
- unsigned int getSupportedOptions();
-
-private:
- std::string source, destination;
- ProgressBar progress;
-};
-
-} // namespace ode
-#endif // __ECRYPTFS_ENGINE_H__
-
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+#include <linux/dm-ioctl.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <klay/audit/logger.h>
+
+#include <klay/error.h>
+#include <klay/exception.h>
+#include <klay/filesystem.h>
+
+#include "../../file-footer.h"
+#include "../../ext4-tool.h"
+
+#include "dmcrypt-engine.h"
+
+#define OPTION_INCLUDE_UNUSED_REGION (1 << 0)
+
+namespace ode {
+
+void CryptInfo::init(const std::string &src, const std::string &crypto_name)
+{
+ crypto_type_name = crypto_name;
+ fs_size = getBlkdevSize(src);
+}
+
+long CryptInfo::getFileSystemSize()
+{
+ return fs_size;
+}
+
+std::string CryptInfo::getCryptoTypeName() const
+{
+ return crypto_type_name;
+}
+
+long CryptInfo::getBlkdevSize(const std::string &src)
+{
+ int fd = open(src.c_str(), O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ long fs_size = 0;
+ if ((ioctl(fd, BLKGETSIZE, &fs_size)) == -1)
+ fs_size = 0;
+ close(fd);
+
+ return fs_size;
+}
+
+
+static void convertKeyToHexASCII(const DMCryptEngine::data &key,
+ DMCryptEngine::data &key_ascii)
+{
+ unsigned int i, a;
+ unsigned char nibble;
+
+ for (i = 0, a = 0; i < key.size(); i++, a += 2) {
+ // For each byte, write out two ascii hex digits
+ nibble = (key[i] >> 4) & 0xf;
+ key_ascii[a] = nibble + (nibble > 9 ? 0x37 : 0x30);
+
+ nibble = key[i] & 0xf;
+ key_ascii[a + 1] = nibble + (nibble > 9 ? 0x37 : 0x30);
+ }
+
+ // Add the null termination
+ key_ascii[a] = '\0';
+}
+
+DMCryptEngine::DMCryptEngine(const std::string &src, const std::string &dest, const ProgressBar &prgsBar) :
+ source(src), destination(dest), progressBar(prgsBar)
+{
+ // 1. Get Real Block device(src)'s infomation
+ cryptInfo.init(src, "aes-cbc-essiv:sha256");
+}
+
+DMCryptEngine::~DMCryptEngine()
+{
+}
+
+static void ioctlInit(struct dm_ioctl *io, size_t dataSize, const char *name, unsigned flags)
+{
+ memset(io, 0, dataSize);
+ io->data_size = dataSize;
+ io->data_start = sizeof(struct dm_ioctl);
+ io->version[0] = 4;
+ io->version[1] = 0;
+ io->version[2] = 0;
+ io->flags = flags;
+ if (name) {
+ memset(io->name, 0, sizeof(io->name));
+ strncpy(io->name, name, sizeof(io->name) - 1);
+ }
+}
+
+#define DM_CRYPT_BUF_SIZE 4096
+#define DM_LABEL "userdata"
+
+static const std::string createCryptoBlkDev(const std::string &real_blkdev, const std::string &mount_name, const DMCryptEngine::data &key, long fileSystemSize, std::string cryptoTypeName)
+{
+ int fd = -1;
+
+ std::string crypto_blkdev;
+ ode::DMCryptEngine::data key_ascii(512);
+
+ /*
+ * dm_buffer |-------------------------------------------------| 4096
+ * dm_io |----------| size of dm_ioctl
+ * dm_ts |--------------| size of dm_Target_spec
+ * crypt_params |---------------------|
+ */
+ char dm_buffer[DM_CRYPT_BUF_SIZE]; // first: for dm_io, dm_ts
+ struct dm_ioctl *dm_io;
+ struct dm_target_spec *dm_ts;
+ unsigned int dm_minor;
+
+ char *crypt_params; // protocol for dm-crypt
+
+ // Open dm control IOCTL
+ if ((fd = open("/dev/mapper/control", O_RDWR)) < 0)
+ throw runtime::Exception("Cannot open device-mapper");
+
+ /*
+ * dm_buffer |-------------------------------------------------| 4096
+ * dm_io |----------| size of dm_ioctl
+ */
+ dm_io = (struct dm_ioctl *)dm_buffer;
+
+ // Clean-up dm_ioctl
+ // Create Device (mount_name)
+ ioctlInit(dm_io, DM_CRYPT_BUF_SIZE, mount_name.c_str(), 0);
+ if (ioctl(fd, DM_DEV_CREATE, dm_io)) {
+ close(fd);
+ throw runtime::Exception("Cannot create dm-crypt device");
+ }
+
+ // Clean-up dm_ioctl
+ // Get the device status, in particular, the mount_name of it's device file
+ ioctlInit(dm_io, DM_CRYPT_BUF_SIZE, mount_name.c_str(), 0);
+ if (ioctl(fd, DM_DEV_STATUS, dm_io)) {
+ close(fd);
+ throw runtime::Exception("Cannot retrieve dm-crypt device status");
+ }
+
+ // Store created device into crypto_blkdev
+ dm_minor = (dm_io->dev & 0xff) | ((dm_io->dev >> 12) & 0xfff00);
+ crypto_blkdev = "/dev/dm-" + std::to_string(dm_minor);
+
+ // Load the mapping table for this device
+ dm_ts = (struct dm_target_spec *)&dm_buffer[sizeof(struct dm_ioctl)];
+
+ /*
+ * dm_buffer |-------------------------------------------------| 4096
+ * dm_io |----------| size of dm_ioctl
+ * dm_ts |--------------| size of dm_Target_spec
+ */
+
+ // Force clean-up whole dm_buffer
+ ioctlInit(dm_io, 4096, mount_name.c_str(), 0);
+ dm_io->target_count = 1;
+ dm_ts->status = 0;
+ dm_ts->sector_start = 0;
+ dm_ts->length = fileSystemSize;
+ strcpy(dm_ts->target_type, "crypt");
+
+ // Prepare crypt_params
+ /*
+ * dm_buffer |-------------------------------------------------| 4096
+ * dm_io |----------| size of dm_ioctl
+ * dm_ts |--------------| size of dm_Target_spec
+ * crypt_params |---------------------|
+ */
+
+ crypt_params = dm_buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
+
+ ode::convertKeyToHexASCII(key, key_ascii);
+
+ // Store crypt_params
+ sprintf(crypt_params, "%s %s 0 %s 0", cryptoTypeName.c_str(), key_ascii.data(), real_blkdev.c_str());
+
+ crypt_params += strlen(crypt_params) + 1;
+ // Align to an 8 byte boundary
+ crypt_params = (char *)(((unsigned long)crypt_params + 7) & ~8);
+ dm_ts->next = crypt_params - dm_buffer;
+
+ // Table load
+ if (ioctl(fd, DM_TABLE_LOAD, dm_io) < 0) {
+ close(fd);
+ throw runtime::Exception("Cannot load dm-crypt mapping table.");
+ }
+
+ // Force clean-up whole dm_buffer
+ // Resume this device to activate it
+ ioctlInit(dm_io, 4096, mount_name.c_str(), 0);
+ if (ioctl(fd, DM_DEV_SUSPEND, dm_io)) {
+ close(fd);
+ throw runtime::Exception("Cannot resume the dm-crypt device");
+ }
+
+ // If fd is <0 from a failed open call,
+ // it's safe to just ignore the close error
+ if (fd >= 0)
+ close(fd);
+
+ return crypto_blkdev;
+}
+
+static void destroyCryptoBlkDev(const std::string &mount_name)
+{
+ int fd;
+ char buffer[DM_CRYPT_BUF_SIZE];
+ struct dm_ioctl *io;
+
+ if ((fd = open("/dev/mapper/control", O_RDWR)) < 0)
+ throw runtime::Exception("Cannot open device-mapper");
+
+ io = (struct dm_ioctl *)buffer;
+
+ ioctlInit(io, DM_CRYPT_BUF_SIZE, mount_name.c_str(), 0);
+ if (ioctl(fd, DM_DEV_REMOVE, io)) {
+ close(fd);
+ throw runtime::Exception("Cannot remove dm-crypt device");
+ }
+
+ if (fd >= 0)
+ close(fd);
+}
+
+#define DMCRYPT_KEY_MIN_LEN_BYTE (32)
+#define DMCRYPT_KEY_MIN_LEN_BIT (DMCRYPT_KEY_MIN_LEN_BYTE*8)
+
+static ode::DMCryptEngine::data sanitizeKey(const ode::DMCryptEngine::data &key)
+{
+ if (key.size() < DMCRYPT_KEY_MIN_LEN_BYTE)
+ throw runtime::Exception("Key length isn't enough to be used for dmcrypt");
+ else if (key.size() > DMCRYPT_KEY_MIN_LEN_BYTE)
+ return ode::DMCryptEngine::data(key.begin(), key.begin() + DMCRYPT_KEY_MIN_LEN_BYTE);
+ else
+ return key;
+}
+
+void DMCryptEngine::mount(const DMCryptEngine::data &key, unsigned int options)
+{
+ DMCryptEngine::data sanitized_key = sanitizeKey(key);
+
+ // create crypto type device mapping layer to mount the encrypted partition.
+ const std::string crypto_blkdev = createCryptoBlkDev(source, DM_LABEL, sanitized_key, cryptInfo.getFileSystemSize(), cryptInfo.getCryptoTypeName());
+
+ if (::mount(crypto_blkdev.c_str(), destination.c_str(), "ext4", 0, 0) < 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+}
+
+void DMCryptEngine::umount()
+{
+ if (::umount(destination.c_str()))
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+
+ destroyCryptoBlkDev(DM_LABEL);
+}
+
+void DMCryptEngine::encryptInPlace(const std::string &src_blkdev,
+ const std::string &dst_blkdev,
+ const bool isFastEncEnabled)
+{
+ Ext4Tool ext4tool(src_blkdev);
+ ext4tool.forceCleanUp();
+
+ const unsigned int SRC_BLOCK_SIZE = ext4tool.getBlockSize();
+ const unsigned int SRC_TOTAL_BLOCK_COUNT = ext4tool.getTotalBlockCount();
+ char buff[SRC_BLOCK_SIZE] = {0, };
+
+ runtime::File dst(dst_blkdev, O_WRONLY);
+ runtime::File src(src_blkdev, O_RDONLY);
+
+ for (unsigned int n = 0; n < SRC_TOTAL_BLOCK_COUNT; n++) {
+ if (isFastEncEnabled && ext4tool.isUsedBlock(n) == false)
+ continue;
+
+ src.lseek(n * SRC_BLOCK_SIZE, SEEK_SET);
+ dst.lseek(n * SRC_BLOCK_SIZE, SEEK_SET);
+
+ src.read(buff, SRC_BLOCK_SIZE);
+ dst.write(buff, SRC_BLOCK_SIZE);
+
+ progressBar.update(n, SRC_TOTAL_BLOCK_COUNT, 1);
+ }
+ progressBar.done();
+}
+
+void DMCryptEngine::encrypt(const DMCryptEngine::data &key, unsigned int options)
+{
+ DMCryptEngine::data sanitized_key = sanitizeKey(key);
+
+ // create crypto type device mapping layer to mount the plain partition
+ // should be encrypted here.
+ const std::string crypto_blkdev = createCryptoBlkDev(source, DM_LABEL, sanitized_key, cryptInfo.getFileSystemSize(), cryptInfo.getCryptoTypeName());
+
+ bool isFastEncEnabled = true;
+ if (options == OPTION_INCLUDE_UNUSED_REGION)
+ isFastEncEnabled = false;
+
+ INFO("FastEncryption: " + std::string(isFastEncEnabled ? "Enabled" : "Disabled"));
+
+ // We always do In-place encryption
+ encryptInPlace(source, crypto_blkdev, isFastEncEnabled);
+
+ // remove crypto type device mapper
+ destroyCryptoBlkDev(DM_LABEL);
+}
+
+void DMCryptEngine::decrypt(const DMCryptEngine::data &key, unsigned int options)
+{
+ DMCryptEngine::data sanitized_key = sanitizeKey(key);
+
+ // create crypto type device mapping layer to mount the plain partition
+ // should be encrypted here.
+ const std::string crypto_blkdev = createCryptoBlkDev(source, DM_LABEL, sanitized_key, cryptInfo.getFileSystemSize(), cryptInfo.getCryptoTypeName());
+
+ bool isFastEncEnabled = true;
+ if (options == OPTION_INCLUDE_UNUSED_REGION)
+ isFastEncEnabled = false;
+
+ INFO("FastEncryption: " + std::string(isFastEncEnabled ? "Enabled" : "Disabled"));
+
+ // We always do In-place encryption
+ encryptInPlace(crypto_blkdev, source, isFastEncEnabled);
+
+ // remove crypto type device mapper
+ destroyCryptoBlkDev(DM_LABEL);
+}
+
+bool DMCryptEngine::isKeyMetaSet()
+{
+ return FileFooter::exist(source);
+}
+
+const DMCryptEngine::data DMCryptEngine::getKeyMeta()
+{
+ return FileFooter::read(source);
+}
+
+void DMCryptEngine::setKeyMeta(const data &meta)
+{
+ FileFooter::write(source, meta);
+}
+
+void DMCryptEngine::clearKeyMeta()
+{
+ FileFooter::clear(source);
+}
+
+unsigned int DMCryptEngine::getSupportedOptions()
+{
+ return OPTION_INCLUDE_UNUSED_REGION;
+}
+
+} // namespace ode
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __DMCRYPT_ENGINE_H__
+#define __DMCRYPT_ENGINE_H__
+
+#include <vector>
+#include <string>
+
+#include "progress-bar.h"
+
+namespace ode {
+
+class CryptInfo {
+public:
+ void init(const std::string &src, const std::string &crypto_name);
+ long getFileSystemSize();
+ std::string getCryptoTypeName() const;
+
+private:
+ long getBlkdevSize(const std::string &src);
+
+private:
+ // TODO(seok85.hong): support fast-encryption
+ long fs_size;
+ std::string crypto_type_name;
+};
+
+
+class DMCryptEngine final {
+public:
+ DMCryptEngine(const std::string &src, const std::string &dest, const ProgressBar &prgsBar);
+ DMCryptEngine(const DMCryptEngine &) = delete;
+ DMCryptEngine(DMCryptEngine &&) = delete;
+ ~DMCryptEngine();
+
+ DMCryptEngine &operator=(const DMCryptEngine &) = delete;
+ DMCryptEngine &operator=(DMCryptEngine &&) = delete;
+
+ const std::string &getSource()
+ {
+ return source;
+ }
+
+ const std::string &getDestination()
+ {
+ return destination;
+ }
+
+ typedef std::vector<unsigned char> data;
+
+ void mount(const data &key, unsigned int options);
+ void umount();
+
+ void encrypt(const data &key, unsigned int options);
+ void decrypt(const data &key, unsigned int options);
+
+ bool isKeyMetaSet();
+ const data getKeyMeta();
+ void setKeyMeta(const data &data);
+ void clearKeyMeta();
+
+ unsigned int getSupportedOptions();
+
+private:
+ void encryptInPlace(const std::string &src_blkdev,
+ const std::string &dst_blkdev,
+ const bool isFastEncEnabled);
+
+private:
+ std::string source, destination;
+ CryptInfo cryptInfo;
+ ProgressBar progressBar;
+};
+
+} // namespace ode
+#endif // __DMCRYPT_ENGINE_H__
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+#include <iomanip>
+
+#include <unistd.h>
+#include <sys/vfs.h>
+#include <sys/mount.h>
+
+#include <klay/error.h>
+#include <klay/exception.h>
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
+
+#include "../../kernel-keyring.h"
+#include "../../file-footer.h"
+
+#include "ecryptfs-engine.h"
+
+#define OPTION_ONLY_NEW_FILE (1 << 0)
+#define OPTION_EXCEPT_FOR_MEDIA_FILE (1 << 1)
+
+#define SUPPORTED_OPTIONS OPTION_ONLY_NEW_FILE
+
+#define MEDIA_EXCLUSION_LIST "temp_video/Camera/DCIM:mp3|mpga|m4a|mp4|wav|amr|awb|wma|ogg|oga|aac|mka|flac|3gp|3ga|mid|midi|xmf|rtttl|rtx|ota|smf|spm|imy|mpeg|m4v|3gp|3gpp|3g2|3gpp2|wmv|asf|mkv|webm|ts|avi|jpg|jpeg|gif|png|bmp|wbmp|divx|flv|ac3|mov|tiff|f4v|mpeg3|voice"
+
+#define CIPHER_MODE "aes"
+#define ENCRYPTION_CHECKER_NAME ".ecryptfs_encrypted"
+
+
+#define ECRYPTFS_VERSION_MAJOR 0x00
+#define ECRYPTFS_VERSION_MINOR 0x04
+#define ECRYPTFS_VERSION ((ECRYPTFS_VERSION_MAJOR << 8) | ECRYPTFS_VERSION_MINOR)
+
+#define ECRYPTFS_MAX_KEY_BYTES 64
+#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
+#define ECRYPTFS_SIG_SIZE 8
+#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
+#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
+#define ECRYPTFS_SALT_SIZE 8
+#define ECRYPTFS_MAX_KEY_MOD_NAME_BYTES 16
+
+struct ecryptfs_session_key {
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
+#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
+#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
+ int32_t flags;
+ int32_t encrypted_key_size;
+ int32_t decrypted_key_size;
+ uint8_t encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+ uint8_t decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
+};
+
+struct ecryptfs_password {
+ int32_t password_bytes;
+ int32_t hash_algo;
+ int32_t hash_iterations;
+ int32_t session_key_encryption_key_bytes;
+#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
+#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
+ uint32_t flags;
+ uint8_t session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+ uint8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+ uint8_t salt[ECRYPTFS_SALT_SIZE];
+};
+
+struct ecryptfs_private_key {
+ uint32_t key_size;
+ uint32_t data_len;
+ uint8_t signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+ char key_mod_alias[ECRYPTFS_MAX_KEY_MOD_NAME_BYTES + 1];
+ uint8_t data[];
+};
+
+enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
+
+struct ecryptfs_auth_tok {
+ uint16_t version;
+ uint16_t token_type;
+#define ECRYPTFS_ENCRYPT_ONLY 0x00000001
+ uint32_t flags;
+ struct ecryptfs_session_key session_key;
+ uint8_t reserved[32];
+ union {
+ struct ecryptfs_password password;
+ struct ecryptfs_private_key private_key;
+ } token;
+} __attribute__((packed));
+
+#if 0
+#define ECRYPTFS_IOCTL_GET_ATTRIBUTES _IOR('l', 0x10, unsigned int)
+#define ECRYPTFS_WAS_ENCRYPTED 0x0080
+#define ECRYPTFS_WAS_ENCRYPTED_OTHER_DEVICE 0x0100
+#endif
+
+#define ECRYPTFS_AUTH_TOKEN_TYPE "user"
+
+namespace ode {
+
+namespace {
+
+unsigned long long getAvailableSpace(const std::string& mountPoint)
+{
+ struct statfs statbuf;
+ if (::statfs(mountPoint.c_str(), &statbuf)) {
+ throw runtime::Exception("Failed to access " + mountPoint);
+ }
+
+ return (unsigned long long)statbuf.f_bfree * statbuf.f_bsize;
+}
+
+bool wasEncrypted(const std::string &path)
+{
+#ifdef ECRYPTFS_IOCTL_GET_ATTRIBUTES
+ unsigned int attrs = 0;
+ bool ret = false;
+ int fd = 0;
+
+ fd = ::open(path.c_str(), O_RDWR);
+ if (fd < 0) {
+ throw runtime::Exception("Failed to open " + path);
+ }
+
+ if (::ioctl(fd, ECRYPTFS_IOCTL_GET_ATTRIBUTES, &attrs) == 0 &&
+ (attrs & ECRYPTFS_WAS_ENCRYPTED)) {
+ ret = true;
+ }
+ ::close(fd);
+
+ return ret;
+#else
+ return true;
+#endif
+}
+
+unsigned long long getEncryptedSize(const runtime::File &file) {
+ unsigned long long originalSize = file.size();
+ unsigned long long result = 0;
+
+ if (originalSize % 4096) {
+ originalSize = (1 + originalSize / 4096) * 4096;
+ }
+
+#ifdef ECRYPTFS_IOCTL_GET_ATTRIBUTES
+ if (wasEncrypted(file.getPath())) {
+ result = originalSize;
+ } else {
+#endif
+ result = originalSize + 2 * 4096;
+#ifdef ECRYPTFS_IOCTL_GET_ATTRIBUTES
+ }
+#endif
+
+ //TODO : block size have to not hard-coded.
+ // If there is a better way, the followings have to be changed.
+ unsigned int blockSize = 4096;
+ if (result % blockSize) {
+ result = (1 + result / blockSize) * blockSize;
+ }
+
+ return result;
+}
+
+unsigned long long getDecryptedSize(const runtime::File &file) {
+ unsigned long long originalSize = file.size();
+ unsigned long long result = originalSize;
+
+ if (wasEncrypted(file.getPath())) {
+ if (originalSize > 2 * 4096) {
+ result = originalSize - 2 * 4096;
+ }
+ }
+
+ result = originalSize;
+
+ //TODO : block size have to not hard-coded.
+ // If there is a better way, the followings have to be changed.
+ unsigned int blockSize = 4096;
+ if (result % blockSize) {
+ result = (1 + result / blockSize) * blockSize;
+ }
+
+ return result;
+}
+
+bool isEnoughToCopyInPlace(const std::string& path,
+ const std::function<unsigned long long(const runtime::File&)> getSizeFunc)
+{
+ unsigned long long availableSpace = getAvailableSpace(path);
+
+ std::function<bool(const std::string &path)> check;
+ check = [&check, &getSizeFunc, availableSpace](const std::string &path) {
+ for (runtime::DirectoryIterator iter(path), end;
+ iter != end; ++iter) {
+ if (iter->isDirectory()) {
+ if (!check(iter->getPath())) {
+ return false;
+ }
+ } else if (getSizeFunc(*iter) > availableSpace) {
+ //TODO : have to consider changing file size
+ // when encrypt/decrypt
+ return false;
+ }
+ }
+ return true;
+ };
+
+ return check(path);
+}
+
+void copyInPlace(const std::string& source, const std::string& destination,
+ const std::string& temp,
+ const std::function<bool(const std::string&)> &isTarget,
+ const std::function<void(unsigned long long)> &addProgress)
+{
+ for (runtime::DirectoryIterator iter(source), end;
+ iter != end; ++iter) {
+ if (iter->isDirectory()) {
+ copyInPlace(iter->getPath(), destination + "/" + iter->getName(),
+ temp, isTarget, addProgress);
+ } else if (isTarget(iter->getPath())) {
+ std::string tempFilePath = temp + "/" + iter->getName();
+ std::string destFilePath = destination + "/" + iter->getName();
+
+ iter->copyTo(tempFilePath);
+ iter->remove();
+ if (::rename(tempFilePath.c_str(), destFilePath.c_str()) != 0) {
+ throw runtime::Exception("Failed to rename from " + tempFilePath + " to " + destFilePath);
+ }
+
+ addProgress(iter->size());
+ }
+ }
+}
+
+void ecryptfsMount(const std::string &source, const std::string &destination, const std::vector<unsigned char> &key, unsigned int options)
+{
+ ecryptfs_auth_tok payload;
+ std::string mountOption;
+
+ ::memset(&(payload), 0, sizeof(ecryptfs_auth_tok));
+
+ payload.version = ECRYPTFS_VERSION;
+ payload.token_type = ECRYPTFS_PASSWORD;
+ payload.token.password.flags = ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
+ payload.token.password.session_key_encryption_key_bytes =
+ (ECRYPTFS_MAX_KEY_BYTES > key.size())? key.size() :
+ ECRYPTFS_MAX_KEY_BYTES;
+ ::memcpy(payload.token.password.session_key_encryption_key, key.data(),
+ payload.token.password.session_key_encryption_key_bytes);
+
+ std::stringstream signature;
+ signature<< std::hex << std::setfill('0') << std::setw(2);
+ for (unsigned int byte : key) {
+ signature << byte;
+ }
+ for (int i = key.size(); i < ECRYPTFS_SIG_SIZE; i++) {
+ signature << (unsigned int) 0;
+ }
+ ::memcpy((char *)payload.token.password.signature,
+ signature.str().c_str(), ECRYPTFS_PASSWORD_SIG_SIZE);
+
+ if (KernelKeyRing::search(KEY_SPEC_USER_KEYRING, ECRYPTFS_AUTH_TOKEN_TYPE,
+ (char *)payload.token.password.signature, 0) < 0) {
+ if (KernelKeyRing::add(ECRYPTFS_AUTH_TOKEN_TYPE,
+ (char *)payload.token.password.signature,
+ (void *)&payload, sizeof(payload),
+ KEY_SPEC_USER_KEYRING) < 0) {
+ throw runtime::Exception("Unable to add token to keyring.");
+ }
+ }
+
+ mountOption = "ecryptfs_passthrough"
+ ",ecryptfs_cipher=" CIPHER_MODE
+ ",ecryptfs_sig=" + std::string((char *)payload.token.password.signature) +
+ ",ecryptfs_key_bytes=" + std::to_string(payload.token.password.session_key_encryption_key_bytes);
+
+ if (options & OPTION_EXCEPT_FOR_MEDIA_FILE) {
+ mountOption += ",ecryptfs_enable_filtering=" MEDIA_EXCLUSION_LIST;
+ }
+
+ INFO("option = " + mountOption);
+ INFO("source = " + source);
+ INFO("dest = " + destination);
+
+ if (::mount(source.c_str(), destination.c_str(), "ecryptfs", MS_NODEV,
+ mountOption.c_str()) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+void ecryptfsUmount(const std::string &destination)
+{
+ if (::umount(destination.c_str()) != 0) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ //TODO : remove key from keyring
+}
+
+} // namespace
+
+EcryptfsEngine::EcryptfsEngine(const std::string &src, const std::string &dest, const ProgressBar &prg) :
+ source(src), destination(dest), progress(prg)
+{
+}
+
+EcryptfsEngine::~EcryptfsEngine()
+{
+}
+
+void EcryptfsEngine::mount(const data &key, unsigned int options)
+{
+ ecryptfsMount(source, destination, key, options);
+}
+
+void EcryptfsEngine::umount()
+{
+ ecryptfsUmount(destination);
+}
+
+void EcryptfsEngine::encrypt(const data &key, unsigned int options)
+{
+ if (!isEnoughToCopyInPlace(source, getDecryptedSize)) {
+ throw runtime::Exception("No space to encryption");
+ }
+
+ progress.update(0);
+
+ try {
+ ecryptfsMount(source, destination, key, options);
+ } catch (runtime::Exception &e) {
+ throw runtime::Exception("Failed to mount - " + std::string(e.what()));
+ }
+
+ try {
+ unsigned long long totalSize = getAvailableSpace(source), current;
+ runtime::File tempDir(destination + "/" ENCRYPTION_CHECKER_NAME);
+
+ tempDir.makeDirectory();
+ if (!(options & OPTION_ONLY_NEW_FILE)) {
+ copyInPlace(destination, destination, tempDir.getPath(),
+ [](const std::string &file) {
+ return true;
+ },
+ [¤t, &totalSize, this](unsigned long long size) {
+ current += size;
+ this->progress.update(current * 100 / totalSize);
+ });
+ }
+ } catch (runtime::Exception &e) {
+ try {
+ ecryptfsUmount(destination);
+ } catch (runtime::Exception &e) {}
+ throw runtime::Exception("Failed to encrypt file - " + std::string(e.what()));
+ }
+
+ sync();
+
+ progress.done();
+}
+
+void EcryptfsEngine::decrypt(const data &key, unsigned int options)
+{
+ if (!isEnoughToCopyInPlace(destination, getEncryptedSize)) {
+ throw runtime::Exception("No space to encryption");
+ }
+
+ progress.update(0);
+
+ try {
+ unsigned long long totalSize = getAvailableSpace(source), current;
+ runtime::File tempDir(source + "/" ENCRYPTION_CHECKER_NAME);
+ runtime::File tempMountpoint(tempDir.getPath() + "/mount");
+
+ tempMountpoint.makeDirectory();
+ ecryptfsMount(source, tempMountpoint.getPath(), key, 0);
+
+ copyInPlace(tempMountpoint.getPath(), source,
+ tempDir.getPath(), wasEncrypted,
+ [¤t, &totalSize, this](unsigned long long size) {
+ current += size;
+ this->progress.update(current * 100 / totalSize);
+ });
+ ecryptfsUmount(tempMountpoint.getPath());
+
+ tempDir.remove(true);
+ } catch (runtime::Exception &e) {
+ throw runtime::Exception("Failed to decrypt file - " + std::string(e.what()));
+ }
+
+ sync();
+
+ progress.done();
+}
+
+bool EcryptfsEngine::isKeyMetaSet()
+{
+ return FileFooter::exist(source);
+}
+
+const EcryptfsEngine::data EcryptfsEngine::getKeyMeta()
+{
+ return FileFooter::read(source);
+}
+
+void EcryptfsEngine::setKeyMeta(const data &meta)
+{
+ FileFooter::write(source, meta);
+}
+
+void EcryptfsEngine::clearKeyMeta()
+{
+ FileFooter::clear(source);
+}
+
+unsigned int EcryptfsEngine::getSupportedOptions()
+{
+ return SUPPORTED_OPTIONS;
+}
+
+} // namespace ode
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __ECRYPTFS_ENGINE_H__
+#define __ECRYPTFS_ENGINE_H__
+
+#include <vector>
+#include <string>
+
+#include "progress-bar.h"
+
+namespace ode {
+
+class EcryptfsEngine final {
+public:
+ EcryptfsEngine(const std::string& src, const std::string& dest, const ProgressBar& prgs);
+ EcryptfsEngine(const EcryptfsEngine&) = delete;
+ EcryptfsEngine(EcryptfsEngine&&) = delete;
+ ~EcryptfsEngine();
+
+ EcryptfsEngine& operator=(const EcryptfsEngine&) = delete;
+ EcryptfsEngine& operator=(EcryptfsEngine&&) = delete;
+
+ const std::string& getSource()
+ {
+ return source;
+ }
+
+ const std::string& getDestination()
+ {
+ return destination;
+ }
+
+ typedef std::vector<unsigned char> data;
+
+ void mount(const data& key, unsigned int);
+ void umount();
+
+ void encrypt(const data& key, unsigned int);
+ void decrypt(const data& key, unsigned int);
+
+ bool isKeyMetaSet();
+ const data getKeyMeta();
+ void setKeyMeta(const data &data);
+ void clearKeyMeta();
+
+ unsigned int getSupportedOptions();
+
+private:
+ std::string source, destination;
+ ProgressBar progress;
+};
+
+} // namespace ode
+#endif // __ECRYPTFS_ENGINE_H__
+
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+#include <iostream>
+#include <string>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/keyctl.h>
+#include <sys/mount.h>
+#include <sys/xattr.h>
+#include <sys/syscall.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sendfile.h>
+
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
+#include <klay/error.h>
+#include <klay/exception.h>
+
+#include "../../file-footer.h"
+#include "../../key-manager/key-generator.h"
+
+#include "ext4-engine.h"
+
+namespace ode {
+
+#define EXT4_MAX_KEY_SIZE 64
+#define EXT4_KEY_DESCRIPTOR_SIZE 8
+#define EXT4_KEY_DESC_PREFIX_SIZE 5
+#define EXT4_KEY_REF_STR_BUF_SIZE ((EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1)
+#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
+#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
+
+/* special process keyring shortcut IDs */
+#define KEY_SPEC_THREAD_KEYRING -1
+#define KEY_SPEC_PROCESS_KEYRING -2
+#define KEY_SPEC_SESSION_KEYRING -3
+#define KEY_SPEC_USER_KEYRING -4
+#define KEY_SPEC_USER_SESSION_KEYRING -5
+#define KEY_SPEC_GROUP_KEYRING -6
+
+#define KEYCTL_GET_KEYRING_ID 0
+#define KEYCTL_SEARCH 10
+
+ /* Encryption algorithms */
+#define EXT4_ENCRYPTION_MODE_INVALID 0
+#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1
+#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2
+#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3
+#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4
+
+#define SMACK_LABEL_LEN_MAX 255
+struct ext4_encryption_policy {
+ char version;
+ char contents_encryption_mode;
+ char filenames_encryption_mode;
+ char flags;
+ char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
+}__attribute__((__packed__));
+
+struct ext4_encryption_key {
+ unsigned int mode;
+ char raw[EXT4_MAX_KEY_SIZE];
+ unsigned int size;
+} __attribute__((__packed__));
+
+/* for now, It only suits for "/opt/usr" */
+namespace {
+ std::string secondMountPoint("/opt/usr_encrypt");
+ std::string bindMountPoint("/opt/usr_encrypt/secure");
+ std::string ext4KeyringType("logon");
+ std::string smackAccessLabel("security.SMACK64");
+ long long totalSize = 0;
+ long long curSize = 0;
+}
+
+const Ext4Engine::data generateKeyDesc(const ode::Ext4Engine::data& key)
+{
+ Ext4Engine::data keyRef1 = ode::KeyGenerator::SHA512(key);
+ Ext4Engine::data keyRef2 = ode::KeyGenerator::SHA512(keyRef1);
+ Ext4Engine::data ret(keyRef2.begin(), keyRef2.begin()+EXT4_KEY_DESCRIPTOR_SIZE);
+
+ return ret;
+}
+
+const Ext4Engine::data generateKeyRefStr(const Ext4Engine::data& key)
+{
+ Ext4Engine::data ret(EXT4_KEY_REF_STR_BUF_SIZE);
+ Ext4Engine::data keyDesc = generateKeyDesc(key);
+
+ int i, a;
+ unsigned char nibble;
+ for (i=0, a=0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++, a+=2) {
+ nibble = (keyDesc[i] >> 4) & 0xf;
+ if (nibble <= 9) ret[a] = '0' + nibble;
+ else ret[a] = 'a' + nibble - 10;
+ nibble = keyDesc[i] & 0xf;
+ if (nibble <= 9) ret[a+1] = '0' + nibble;
+ else ret[a+1] = 'a' + nibble - 10;
+ }
+
+ ret[a] = '\0';
+
+ return ret;
+}
+
+void addKeyToKeyring(const Ext4Engine::data& key)
+{
+ struct ext4_encryption_key ext4Key;
+ Ext4Engine::data keyRefStr(EXT4_KEY_REF_STR_BUF_SIZE);
+ keyRefStr = generateKeyRefStr(key);
+ std::string keyRef(keyRefStr.begin(), keyRefStr.end()), keyRefFull;
+ int keyringId, ret;
+
+ keyringId = ::syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 0);
+ if (keyringId == -1)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+
+ keyRefFull = "ext4:" + keyRef;
+ ret = ::syscall(__NR_keyctl, KEYCTL_SEARCH, keyringId, ext4KeyringType.c_str(), keyRefFull.c_str(), 0);
+ if (ret != -1) {
+ INFO("Key with descriptor already exist");
+ return;
+ }
+ ext4Key.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+ ::memcpy(ext4Key.raw, key.data(), EXT4_MAX_KEY_SIZE);
+ std::string ext4KeyRaw = ext4Key.raw;
+ ext4Key.size = EXT4_MAX_KEY_SIZE;
+
+ ret = ::syscall(__NR_add_key, ext4KeyringType.c_str(), keyRefFull.c_str(),
+ (void *)&ext4Key, sizeof(ext4Key), keyringId);
+
+ if (ret == -1) {
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+}
+
+static void copySmackLabel(std::string& srcPath, std::string& destPath)
+{
+ Ext4Engine::data smackLabel(SMACK_LABEL_LEN_MAX + 1);
+
+ if (::getxattr(srcPath.c_str(), smackAccessLabel.c_str(), (unsigned char*)smackLabel.data(), SMACK_LABEL_LEN_MAX + 1) == -1)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+
+ if (::setxattr(destPath.c_str(), smackAccessLabel.c_str(), smackLabel.data(), smackLabel.size(), 0) == -1)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+}
+
+int Ext4Engine::copy(std::string& src, std::string& dest)
+{
+ int readFd, writeFd, ret;
+ struct stat st;
+
+ ret = ::stat(src.c_str(), &st);
+ if (ret != 0) {
+ throw runtime::Exception(src + runtime::GetSystemErrorMessage());
+ }
+
+ readFd = ::open(src.c_str(), O_RDONLY);
+ if (readFd < 0)
+ throw runtime::Exception(src + runtime::GetSystemErrorMessage());
+
+ writeFd = ::open(dest.c_str(), O_WRONLY | O_CREAT, st.st_mode);
+ if (writeFd < 0)
+ throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
+ copySmackLabel(src, dest);
+ if (::chown(dest.c_str(), st.st_uid, st.st_gid) == -1)
+ throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
+ if (::sendfile(writeFd, readFd, 0, st.st_size) == -1)
+ return 1;
+
+ /* progress bar update */
+ curSize += st.st_size;
+ INFO("curSize is " + std::to_string(curSize));
+ progressBar.update(curSize, totalSize, 1);
+
+ if (::fsync(writeFd) != 0)
+ throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
+
+ if (::posix_fadvise(writeFd, 0, st.st_size, POSIX_FADV_DONTNEED) < 0)
+ throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
+
+ ::close(readFd);
+ ::close(writeFd);
+ return 0;
+}
+
+static void preScanDir(std::string& dir)
+{
+ DIR* d;
+
+ d = ::opendir(dir.c_str());
+
+ if (!d)
+ throw runtime::Exception(dir + runtime::GetSystemErrorMessage());
+
+ while(1) {
+ struct dirent* entry;
+ std::string dName;
+
+ entry = ::readdir(d);
+ if (!entry) {
+ break;
+ }
+ dName = entry->d_name;
+ if (!(entry->d_type & DT_DIR)) {
+ std::string file = dir + "/" + dName;
+ struct stat st;
+ int statRet;
+
+ statRet = ::stat(file.c_str(), &st);
+ if (statRet != 0)
+ throw runtime::Exception(file + runtime::GetSystemErrorMessage());
+ INFO("[preListDir] " + file + " totalSize = " + std::to_string(totalSize) + " " +std::to_string(st.st_size));
+ totalSize += st.st_size;
+ }
+
+ if (entry->d_type & DT_DIR) {
+ if (dName.compare(".") != 0 && dName.compare("..") != 0) {
+ std::string path;
+
+ path = dir + "/" + dName;
+
+
+ if (path.size() >= PATH_MAX)
+ throw runtime::Exception(path + " :path length has got too long");
+
+ preScanDir(path);
+ }
+ }
+ }
+
+ if (::closedir(d))
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+
+}
+
+void Ext4Engine::listDir(std::string& source, std::string& dest, bool excludeFlag)
+{
+ DIR* d;
+
+ if (excludeFlag && source.compare(0, bindMountPoint.size(), bindMountPoint) == 0)
+ return;
+
+ d = ::opendir(source.c_str());
+
+ if (!d)
+ throw runtime::Exception(source + runtime::GetSystemErrorMessage());
+
+ while(1) {
+ struct dirent* entry;
+ std::string dName;
+
+ entry = ::readdir(d);
+ if (!entry) {
+ break;
+ }
+ dName = entry->d_name;
+ if (!(entry->d_type & DT_DIR)) {
+ std::string srcFile = source + "/" + dName;
+ std::string destFile = dest + "/" +dName;
+ copy(srcFile, destFile);
+
+ if (::remove(srcFile.c_str()) != 0)
+ ERROR("file remove failed");
+ }
+
+ if (entry->d_type & DT_DIR) {
+ if (dName.compare(".") != 0 && dName.compare("..") != 0) {
+ std::string pathS, pathD;
+
+ pathS = source + "/" + dName;
+ pathD = dest + "/" +dName;
+
+ /* make new directory */
+ int mkdirRet, statRet;
+ struct stat st;
+ statRet = ::stat(pathS.c_str(), &st);
+ if (statRet != 0)
+ throw runtime::Exception(pathS + runtime::GetSystemErrorMessage());
+
+ if (excludeFlag) {
+ if (pathS.compare(bindMountPoint) != 0) {
+ mkdirRet = ::mkdir(pathD.c_str(), st.st_mode);
+ if (mkdirRet != 0)
+ throw runtime::Exception(pathS + runtime::GetSystemErrorMessage());
+ copySmackLabel(pathS, pathD);
+ if (::chown(pathD.c_str(), st.st_uid, st.st_gid) == -1)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+ } else {
+ mkdirRet = ::mkdir(pathD.c_str(), st.st_mode);
+ if (mkdirRet != 0)
+ throw runtime::Exception(pathD + runtime::GetSystemErrorMessage());
+ copySmackLabel(pathS, pathD);
+ if (::chown(pathD.c_str(), st.st_uid, st.st_gid) == -1)
+ throw runtime::Exception(pathD + runtime::GetSystemErrorMessage());
+ }
+ if (pathS.size() >= PATH_MAX)
+ throw runtime::Exception(pathS + " :path length has got too long");
+
+ listDir(pathS, pathD, excludeFlag);
+ }
+ }
+ }
+
+ if (::closedir(d))
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+
+ if (source.compare(secondMountPoint) != 0) {
+ if (::remove(source.c_str()) != 0)
+ throw runtime::Exception(source + runtime::GetSystemErrorMessage());
+ }
+}
+
+static int intLog2(int arg)
+{
+ int l = 0;
+
+ arg >>= 1;
+ while(arg) {
+ l++;
+ arg >>= 1;
+ }
+
+ return l;
+}
+
+static void setPolicy(const std::string& source, const Ext4Engine::data& key)
+{
+ struct ext4_encryption_policy policy;
+ int pad = 4;
+ int fd, rc;
+ Ext4Engine::data descriptor(EXT4_KEY_DESCRIPTOR_SIZE);
+
+ descriptor = generateKeyDesc(key);
+ std::string descStr(descriptor.begin(), descriptor.end());
+
+ fd = ::open(source.c_str(), O_DIRECTORY);
+ if (fd == -1)
+ throw runtime::Exception("invalid path");
+
+ policy.version = 0;
+ policy.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+ policy.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
+ policy.flags = intLog2(pad >> 2);
+ ::memcpy(policy.master_key_descriptor, descriptor.data(), EXT4_KEY_DESCRIPTOR_SIZE);
+
+ rc = ::ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &policy);
+ ::close(fd);
+
+ if (rc)
+ throw runtime::Exception("set policy failed :" + runtime::GetSystemErrorMessage());
+}
+
+static bool prepareEncryptDir(std::string& sourceName, std::string& destName)
+{
+ struct stat dirStat;
+ ::stat(destName.c_str(), &dirStat);
+
+ if (::mkdir(secondMountPoint.c_str(), dirStat.st_mode) != 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ copySmackLabel(destName, secondMountPoint);
+ if (::chown(secondMountPoint.c_str(), dirStat.st_uid, dirStat.st_gid) == -1)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ if (::mount(sourceName.c_str(), secondMountPoint.c_str(), "ext4", 0, 0) < 0) {
+ ::remove(secondMountPoint.c_str());
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ }
+
+ if (::mkdir(bindMountPoint.c_str(), dirStat.st_mode) != 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ copySmackLabel(secondMountPoint, bindMountPoint);
+ if (::chown(bindMountPoint.c_str(), dirStat.st_uid, dirStat.st_gid) == -1)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ return true;
+}
+
+static bool getPolicy(const std::string& dirName)
+{
+ struct ext4_encryption_policy policy;
+ int fd, rc;
+
+ fd = ::open(dirName.c_str(), O_DIRECTORY);
+ if (fd == -1)
+ return false;
+
+ rc = ::ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &policy);
+ close(fd);
+ if (rc) {
+ ERROR("ioctl error");
+ return false;
+ }
+ return true;
+}
+
+Ext4Engine::Ext4Engine(const std::string& src, const std::string& dest, const ProgressBar &prgsBar) :
+ source(src), destination(dest), progressBar(prgsBar)
+{
+}
+
+Ext4Engine::~Ext4Engine()
+{
+}
+
+void Ext4Engine::mount(const Ext4Engine::data& key, unsigned int options)
+{
+ addKey(key);
+ /* mount : /dev/mmcblk0p21 /opt/usr_encrypt */
+ if (::mount(source.c_str(), secondMountPoint.c_str(), "ext4", 0, 0) < 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ /* bind mount :/opt/usr_encrypt/secure /opt/usr */
+ if (::mount(bindMountPoint.c_str(), destination.c_str(), "ext4", MS_BIND, 0) < 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+}
+
+void Ext4Engine::umount()
+{
+ /* for decrypt, umount /opt/usr */
+ if (::umount(destination.c_str()))
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+}
+
+void Ext4Engine::addKey(const Ext4Engine::data& key)
+{
+ addKeyToKeyring(key);
+}
+
+void Ext4Engine::encrypt(const Ext4Engine::data& key, unsigned int options)
+{
+ std::string sourceDir = getSource();
+ std::string destDir = getDestination();
+ bool copyFlag = false;
+
+ if (!(copyFlag = prepareEncryptDir(sourceDir, destDir)))
+ throw runtime::Exception("prepareEncryptDir failed");
+
+ preScanDir(secondMountPoint);
+ /* key add to keyring */
+ addKeyToKeyring(key);
+ /* set policy */
+ setPolicy(bindMountPoint, key);
+
+ if (copyFlag)
+ listDir(secondMountPoint, bindMountPoint, true);
+ INFO("[ext4 encrypt] copy done");
+
+ progressBar.done();
+ if (::mount(bindMountPoint.c_str(), destDir.c_str(), "ext4", MS_BIND, 0) < 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+}
+
+void Ext4Engine::decrypt(const Ext4Engine::data& key, unsigned int options)
+{
+ std::string destDir = getDestination();
+
+ if (!getPolicy(bindMountPoint))
+ throw runtime::Exception("directory isn't encrypted");
+ addKeyToKeyring(key);
+
+ preScanDir(bindMountPoint);
+
+ listDir(bindMountPoint, secondMountPoint, false);
+ INFO("[ext4 decrypt] copy done");
+ progressBar.done();
+
+ if (::open(bindMountPoint.c_str(), O_RDONLY) != -1)
+ ::remove(bindMountPoint.c_str());
+
+ /* umount /opt/usr_encrypt */
+ if (::umount(secondMountPoint.c_str()))
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+ /* mount /dev/mmcblk0p21 /opt/usr */
+ if (::mount(source.c_str(), destination.c_str(), "ext4", 0, 0) < 0)
+ throw runtime::Exception(runtime::GetSystemErrorMessage());
+
+ if (::open(secondMountPoint.c_str(), O_RDONLY) != -1)
+ ::remove(secondMountPoint.c_str());
+}
+
+bool Ext4Engine::isKeyMetaSet()
+{
+ return FileFooter::exist(source);
+}
+
+const Ext4Engine::data Ext4Engine::getKeyMeta()
+{
+ return FileFooter::read(source);
+}
+
+void Ext4Engine::setKeyMeta(const data &data)
+{
+ FileFooter::write(source, data);
+}
+
+void Ext4Engine::clearKeyMeta()
+{
+ FileFooter::clear(source);
+}
+
+unsigned int Ext4Engine::getSupportedOptions()
+{
+ return 0;
+}
+
+} // namespace ode
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __EXT4_ENGINE_H__
+#define __EXT4_ENGINE_H__
+
+#include <vector>
+#include <string>
+
+#include "progress-bar.h"
+
+namespace ode {
+
+class Ext4Engine final {
+public:
+ Ext4Engine(const std::string& src, const std::string& dest, const ProgressBar &prgsBar);
+ Ext4Engine(const Ext4Engine&) = delete;
+ Ext4Engine(Ext4Engine&&) = delete;
+ ~Ext4Engine();
+
+ Ext4Engine& operator=(const Ext4Engine&) = delete;
+ Ext4Engine& operator=(Ext4Engine&&) = delete;
+
+ const std::string& getSource()
+ {
+ return source;
+ }
+
+ const std::string& getDestination()
+ {
+ return destination;
+ }
+
+ typedef std::vector<unsigned char> data;
+
+ void mount(const data &key, unsigned int options);
+ void umount();
+
+ void addKey(const data &key);
+ void encrypt(const data &key, unsigned int options);
+ void decrypt(const data &key, unsigned int options);
+
+ bool isKeyMetaSet();
+ const data getKeyMeta();
+ void setKeyMeta(const data &data);
+ void clearKeyMeta();
+
+ unsigned int getSupportedOptions();
+
+ int copy(std::string& src, std::string& dest);
+ void listDir(std::string& source, std::string& dest, bool excludeFlag);
+
+private:
+ std::string source, destination;
+ ProgressBar progressBar;
+};
+
+} // namespace ode
+#endif // __EXT4_ENGINE_H__
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include <fstream>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+
+#include <vconf.h>
+#include <klay/filesystem.h>
+#include <klay/exception.h>
+#include <klay/audit/logger.h>
+
+#include "ext4-tool.h"
+#include "block-device.h"
+#include "mmc-engine.h"
+
+namespace ode {
+
+namespace {
+
+int getTotalFileCount(const std::string &path)
+{
+ int total = 0;
+ runtime::DirectoryIterator iter(path), end;
+
+ while (iter != end) {
+ std::string next = path + "/" + iter->getName();
+ runtime::File file(next);
+ if (!file.exists()) {
+ return -1;
+ }
+
+ if (file.isFile()) {
+ total++;
+ } else if (file.isDirectory()) {
+ int subTotal = getTotalFileCount(next);
+ if (subTotal != -1)
+ total += subTotal;
+ }
+ ++iter;
+ }
+ return total;
+}
+
+} /* namespace */
+
+MMCEraseEngine::MMCEraseEngine(const ProgressBar &prgsBar) :
+ progressBar(prgsBar)
+{
+}
+
+MMCEraseEngine::~MMCEraseEngine()
+{
+}
+
+int MMCEraseEngine::cleanDevice(const std::string &path)
+{
+ runtime::File file(path, O_WRONLY);
+ if (!file.exists() || !file.isDevice()) {
+ throw runtime::Exception("Target doesn't exist");
+ }
+
+ BlockDevice blockDevice(path);
+ unsigned totalBlock, blockSize;
+
+ Ext4Tool ext4Tool(path);
+ totalBlock = ext4Tool.getTotalBlockCount();
+ blockSize = (unsigned int)blockDevice.getSize();
+
+ for (unsigned int i = 0; i < totalBlock; i++) {
+ if (!ext4Tool.isUsedBlock(i)) {
+ Block block(i * blockSize, blockSize);
+ blockDevice.discard(block);
+ }
+ progressBar.update(i, totalBlock, 1);
+ }
+
+ progressBar.done();
+ return 0;
+}
+
+int MMCEraseEngine::eraseDevice(const std::string &path)
+{
+ runtime::File file(path, O_WRONLY);
+ if (!file.exists()) {
+ throw runtime::Exception("Target doesn't exist");
+ }
+
+ BlockDevice blockDevice(path);
+ Ext4Tool ext4Tool(blockDevice.getName());
+
+ unsigned int totalBlock = ext4Tool.getTotalBlockCount();
+ unsigned int blockSize = (unsigned int)blockDevice.getSize();
+
+ for (unsigned int i = 0; i < totalBlock; i++) {
+ Block block(i * blockSize, blockSize);
+ blockDevice.discard(block);
+ progressBar.update(i, totalBlock, 1);
+ }
+
+ progressBar.done();
+ return 0;
+}
+
+int MMCEraseEngine::eraseFile(const std::string &path)
+{
+ int ret = 0, fd = 0;
+ int extentBlockCount = 0;
+ char buf[4096] = "";
+ struct fiemap *fmap = (struct fiemap *)buf;
+ struct fiemap_extent *fm_ext = NULL;
+ int count = (sizeof(buf) - sizeof(*fmap)) / sizeof(struct fiemap_extent);
+
+ ::memset(fmap, 0, sizeof(struct fiemap));
+
+ fd = ::open(path.c_str(), O_RDONLY);
+ if (fd < 0) {
+ throw runtime::Exception("cannot open the file");
+ }
+
+ fmap->fm_length = ~0ULL;
+ fmap->fm_flags = 0;
+ fmap->fm_extent_count = count;
+
+ ret = ::ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fmap);
+ if (ret < 0) {
+ ::close(fd);
+ throw runtime::Exception("failed to get a fiemap");
+ }
+
+ ::close(fd);
+
+ fm_ext = &fmap->fm_extents[0];
+ extentBlockCount = (int)fmap->fm_mapped_extents;
+
+ BlockDevice blockDevice(path);
+ for (int i = 0; i < extentBlockCount; i++) {
+ Block block(fm_ext[i].fe_physical, fm_ext[i].fe_length);
+ ret = blockDevice.secDiscard(block);
+ if (ret < 0) {
+ throw runtime::Exception("failed to erase the device");
+ }
+ }
+
+ if (totalFileCount == 1) {
+ progressBar.update(1, extentBlockCount, 1);
+ }
+
+ return ret;
+}
+
+int MMCEraseEngine::eraseDirectory(const std::string &path)
+{
+ runtime::DirectoryIterator iter(path), end;
+
+ while (iter != end) {
+ std::string next = path + "/" + iter->getName();
+ runtime::File file(next);
+ if (!file.exists()) {
+ throw runtime::Exception("Target doesn't exist");
+ }
+
+ if (file.isFile()) {
+ eraseFile(next);
+ ::remove(next.c_str());
+ erasedFileCount++;
+ progressBar.update(erasedFileCount, totalFileCount, 1);
+ } else if (file.isDirectory()) {
+ eraseDirectory(next);
+ }
+ ++iter;
+ }
+
+ eraseFile(path);
+ ::rmdir(path.c_str());
+ return 0;
+}
+
+int MMCEraseEngine::eraseFiles(const std::string &path)
+{
+ runtime::File file(path);
+
+ if (!file.exists()) {
+ throw runtime::Exception("Target doesn't exist");
+ }
+
+ if (file.isFile()) {
+ totalFileCount = 1;
+ eraseFile(path);
+ ::remove(path.c_str());
+ } else {
+ totalFileCount = getTotalFileCount(path);
+ erasedFileCount = 0;
+ eraseDirectory(path);
+ }
+
+ progressBar.done();
+ return 0;
+}
+
+} /* namespace ode */
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __MMC_ERASE_ENGINE_H__
+#define __MMC_ERASE_ENGINE_H__
+
+#include "progress-bar.h"
+
+namespace ode {
+
+class MMCEraseEngine final {
+public:
+ MMCEraseEngine(const ProgressBar &prgsBar);
+ MMCEraseEngine(const MMCEraseEngine &) = delete;
+ MMCEraseEngine(MMCEraseEngine &&) = delete;
+ ~MMCEraseEngine();
+
+ MMCEraseEngine &operator=(const MMCEraseEngine &) = delete;
+ MMCEraseEngine &operator=(MMCEraseEngine &&) = delete;
+
+ int eraseDevice(const std::string &path);
+ int cleanDevice(const std::string &path);
+ int eraseFiles(const std::string &path);
+
+private:
+ int eraseFile(const std::string &path);
+ int eraseDirectory(const std::string &path);
+private:
+ ProgressBar progressBar;
+ int totalFileCount;
+ int erasedFileCount;
+};
+
+} /* namespace ode */
+
+#endif /*__MMC_ERASE_ENGINE_H__*/
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-#include <iostream>
-#include <string>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <linux/keyctl.h>
-#include <sys/mount.h>
-#include <sys/xattr.h>
-#include <sys/syscall.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/sendfile.h>
-
-#include <klay/filesystem.h>
-#include <klay/audit/logger.h>
-#include <klay/error.h>
-#include <klay/exception.h>
-
-#include "../file-footer.h"
-#include "../key-manager/key-generator.h"
-
-#include "ext4-engine.h"
-
-namespace ode {
-
-#define EXT4_MAX_KEY_SIZE 64
-#define EXT4_KEY_DESCRIPTOR_SIZE 8
-#define EXT4_KEY_DESC_PREFIX_SIZE 5
-#define EXT4_KEY_REF_STR_BUF_SIZE ((EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1)
-#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
-#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy)
-
-/* special process keyring shortcut IDs */
-#define KEY_SPEC_THREAD_KEYRING -1
-#define KEY_SPEC_PROCESS_KEYRING -2
-#define KEY_SPEC_SESSION_KEYRING -3
-#define KEY_SPEC_USER_KEYRING -4
-#define KEY_SPEC_USER_SESSION_KEYRING -5
-#define KEY_SPEC_GROUP_KEYRING -6
-
-#define KEYCTL_GET_KEYRING_ID 0
-#define KEYCTL_SEARCH 10
-
- /* Encryption algorithms */
-#define EXT4_ENCRYPTION_MODE_INVALID 0
-#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1
-#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2
-#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3
-#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4
-
-#define SMACK_LABEL_LEN_MAX 255
-struct ext4_encryption_policy {
- char version;
- char contents_encryption_mode;
- char filenames_encryption_mode;
- char flags;
- char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
-}__attribute__((__packed__));
-
-struct ext4_encryption_key {
- unsigned int mode;
- char raw[EXT4_MAX_KEY_SIZE];
- unsigned int size;
-} __attribute__((__packed__));
-
-/* for now, It only suits for "/opt/usr" */
-namespace {
- std::string secondMountPoint("/opt/usr_encrypt");
- std::string bindMountPoint("/opt/usr_encrypt/secure");
- std::string ext4KeyringType("logon");
- std::string smackAccessLabel("security.SMACK64");
- long long totalSize = 0;
- long long curSize = 0;
-}
-
-const Ext4Engine::data generateKeyDesc(const ode::Ext4Engine::data& key)
-{
- Ext4Engine::data keyRef1 = ode::KeyGenerator::SHA512(key);
- Ext4Engine::data keyRef2 = ode::KeyGenerator::SHA512(keyRef1);
- Ext4Engine::data ret(keyRef2.begin(), keyRef2.begin()+EXT4_KEY_DESCRIPTOR_SIZE);
-
- return ret;
-}
-
-const Ext4Engine::data generateKeyRefStr(const Ext4Engine::data& key)
-{
- Ext4Engine::data ret(EXT4_KEY_REF_STR_BUF_SIZE);
- Ext4Engine::data keyDesc = generateKeyDesc(key);
-
- int i, a;
- unsigned char nibble;
- for (i=0, a=0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++, a+=2) {
- nibble = (keyDesc[i] >> 4) & 0xf;
- if (nibble <= 9) ret[a] = '0' + nibble;
- else ret[a] = 'a' + nibble - 10;
- nibble = keyDesc[i] & 0xf;
- if (nibble <= 9) ret[a+1] = '0' + nibble;
- else ret[a+1] = 'a' + nibble - 10;
- }
-
- ret[a] = '\0';
-
- return ret;
-}
-
-void addKeyToKeyring(const Ext4Engine::data& key)
-{
- struct ext4_encryption_key ext4Key;
- Ext4Engine::data keyRefStr(EXT4_KEY_REF_STR_BUF_SIZE);
- keyRefStr = generateKeyRefStr(key);
- std::string keyRef(keyRefStr.begin(), keyRefStr.end()), keyRefFull;
- int keyringId, ret;
-
- keyringId = ::syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 0);
- if (keyringId == -1)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-
- keyRefFull = "ext4:" + keyRef;
- ret = ::syscall(__NR_keyctl, KEYCTL_SEARCH, keyringId, ext4KeyringType.c_str(), keyRefFull.c_str(), 0);
- if (ret != -1) {
- INFO("Key with descriptor already exist");
- return;
- }
- ext4Key.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
- ::memcpy(ext4Key.raw, key.data(), EXT4_MAX_KEY_SIZE);
- std::string ext4KeyRaw = ext4Key.raw;
- ext4Key.size = EXT4_MAX_KEY_SIZE;
-
- ret = ::syscall(__NR_add_key, ext4KeyringType.c_str(), keyRefFull.c_str(),
- (void *)&ext4Key, sizeof(ext4Key), keyringId);
-
- if (ret == -1) {
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- }
-}
-
-static void copySmackLabel(std::string& srcPath, std::string& destPath)
-{
- Ext4Engine::data smackLabel(SMACK_LABEL_LEN_MAX + 1);
-
- if (::getxattr(srcPath.c_str(), smackAccessLabel.c_str(), (unsigned char*)smackLabel.data(), SMACK_LABEL_LEN_MAX + 1) == -1)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-
- if (::setxattr(destPath.c_str(), smackAccessLabel.c_str(), smackLabel.data(), smackLabel.size(), 0) == -1)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-}
-
-int Ext4Engine::copy(std::string& src, std::string& dest)
-{
- int readFd, writeFd, ret;
- struct stat st;
-
- ret = ::stat(src.c_str(), &st);
- if (ret != 0) {
- throw runtime::Exception(src + runtime::GetSystemErrorMessage());
- }
-
- readFd = ::open(src.c_str(), O_RDONLY);
- if (readFd < 0)
- throw runtime::Exception(src + runtime::GetSystemErrorMessage());
-
- writeFd = ::open(dest.c_str(), O_WRONLY | O_CREAT, st.st_mode);
- if (writeFd < 0)
- throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
- copySmackLabel(src, dest);
- if (::chown(dest.c_str(), st.st_uid, st.st_gid) == -1)
- throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
- if (::sendfile(writeFd, readFd, 0, st.st_size) == -1)
- return 1;
-
- /* progress bar update */
- curSize += st.st_size;
- INFO("curSize is " + std::to_string(curSize));
- progressBar.update(curSize, totalSize, 1);
-
- if (::fsync(writeFd) != 0)
- throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
-
- if (::posix_fadvise(writeFd, 0, st.st_size, POSIX_FADV_DONTNEED) < 0)
- throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
-
- ::close(readFd);
- ::close(writeFd);
- return 0;
-}
-
-static void preScanDir(std::string& dir)
-{
- DIR* d;
-
- d = ::opendir(dir.c_str());
-
- if (!d)
- throw runtime::Exception(dir + runtime::GetSystemErrorMessage());
-
- while(1) {
- struct dirent* entry;
- std::string dName;
-
- entry = ::readdir(d);
- if (!entry) {
- break;
- }
- dName = entry->d_name;
- if (!(entry->d_type & DT_DIR)) {
- std::string file = dir + "/" + dName;
- struct stat st;
- int statRet;
-
- statRet = ::stat(file.c_str(), &st);
- if (statRet != 0)
- throw runtime::Exception(file + runtime::GetSystemErrorMessage());
- INFO("[preListDir] " + file + " totalSize = " + std::to_string(totalSize) + " " +std::to_string(st.st_size));
- totalSize += st.st_size;
- }
-
- if (entry->d_type & DT_DIR) {
- if (dName.compare(".") != 0 && dName.compare("..") != 0) {
- std::string path;
-
- path = dir + "/" + dName;
-
-
- if (path.size() >= PATH_MAX)
- throw runtime::Exception(path + " :path length has got too long");
-
- preScanDir(path);
- }
- }
- }
-
- if (::closedir(d))
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-
-}
-
-void Ext4Engine::listDir(std::string& source, std::string& dest, bool excludeFlag)
-{
- DIR* d;
-
- if (excludeFlag && source.compare(0, bindMountPoint.size(), bindMountPoint) == 0)
- return;
-
- d = ::opendir(source.c_str());
-
- if (!d)
- throw runtime::Exception(source + runtime::GetSystemErrorMessage());
-
- while(1) {
- struct dirent* entry;
- std::string dName;
-
- entry = ::readdir(d);
- if (!entry) {
- break;
- }
- dName = entry->d_name;
- if (!(entry->d_type & DT_DIR)) {
- std::string srcFile = source + "/" + dName;
- std::string destFile = dest + "/" +dName;
- copy(srcFile, destFile);
-
- if (::remove(srcFile.c_str()) != 0)
- ERROR("file remove failed");
- }
-
- if (entry->d_type & DT_DIR) {
- if (dName.compare(".") != 0 && dName.compare("..") != 0) {
- std::string pathS, pathD;
-
- pathS = source + "/" + dName;
- pathD = dest + "/" +dName;
-
- /* make new directory */
- int mkdirRet, statRet;
- struct stat st;
- statRet = ::stat(pathS.c_str(), &st);
- if (statRet != 0)
- throw runtime::Exception(pathS + runtime::GetSystemErrorMessage());
-
- if (excludeFlag) {
- if (pathS.compare(bindMountPoint) != 0) {
- mkdirRet = ::mkdir(pathD.c_str(), st.st_mode);
- if (mkdirRet != 0)
- throw runtime::Exception(pathS + runtime::GetSystemErrorMessage());
- copySmackLabel(pathS, pathD);
- if (::chown(pathD.c_str(), st.st_uid, st.st_gid) == -1)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- }
- } else {
- mkdirRet = ::mkdir(pathD.c_str(), st.st_mode);
- if (mkdirRet != 0)
- throw runtime::Exception(pathD + runtime::GetSystemErrorMessage());
- copySmackLabel(pathS, pathD);
- if (::chown(pathD.c_str(), st.st_uid, st.st_gid) == -1)
- throw runtime::Exception(pathD + runtime::GetSystemErrorMessage());
- }
- if (pathS.size() >= PATH_MAX)
- throw runtime::Exception(pathS + " :path length has got too long");
-
- listDir(pathS, pathD, excludeFlag);
- }
- }
- }
-
- if (::closedir(d))
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-
- if (source.compare(secondMountPoint) != 0) {
- if (::remove(source.c_str()) != 0)
- throw runtime::Exception(source + runtime::GetSystemErrorMessage());
- }
-}
-
-static int intLog2(int arg)
-{
- int l = 0;
-
- arg >>= 1;
- while(arg) {
- l++;
- arg >>= 1;
- }
-
- return l;
-}
-
-static void setPolicy(const std::string& source, const Ext4Engine::data& key)
-{
- struct ext4_encryption_policy policy;
- int pad = 4;
- int fd, rc;
- Ext4Engine::data descriptor(EXT4_KEY_DESCRIPTOR_SIZE);
-
- descriptor = generateKeyDesc(key);
- std::string descStr(descriptor.begin(), descriptor.end());
-
- fd = ::open(source.c_str(), O_DIRECTORY);
- if (fd == -1)
- throw runtime::Exception("invalid path");
-
- policy.version = 0;
- policy.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
- policy.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
- policy.flags = intLog2(pad >> 2);
- ::memcpy(policy.master_key_descriptor, descriptor.data(), EXT4_KEY_DESCRIPTOR_SIZE);
-
- rc = ::ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &policy);
- ::close(fd);
-
- if (rc)
- throw runtime::Exception("set policy failed :" + runtime::GetSystemErrorMessage());
-}
-
-static bool prepareEncryptDir(std::string& sourceName, std::string& destName)
-{
- struct stat dirStat;
- ::stat(destName.c_str(), &dirStat);
-
- if (::mkdir(secondMountPoint.c_str(), dirStat.st_mode) != 0)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- copySmackLabel(destName, secondMountPoint);
- if (::chown(secondMountPoint.c_str(), dirStat.st_uid, dirStat.st_gid) == -1)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- if (::mount(sourceName.c_str(), secondMountPoint.c_str(), "ext4", 0, 0) < 0) {
- ::remove(secondMountPoint.c_str());
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- }
-
- if (::mkdir(bindMountPoint.c_str(), dirStat.st_mode) != 0)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- copySmackLabel(secondMountPoint, bindMountPoint);
- if (::chown(bindMountPoint.c_str(), dirStat.st_uid, dirStat.st_gid) == -1)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- return true;
-}
-
-static bool getPolicy(const std::string& dirName)
-{
- struct ext4_encryption_policy policy;
- int fd, rc;
-
- fd = ::open(dirName.c_str(), O_DIRECTORY);
- if (fd == -1)
- return false;
-
- rc = ::ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &policy);
- close(fd);
- if (rc) {
- ERROR("ioctl error");
- return false;
- }
- return true;
-}
-
-Ext4Engine::Ext4Engine(const std::string& src, const std::string& dest, const ProgressBar &prgsBar) :
- source(src), destination(dest), progressBar(prgsBar)
-{
-}
-
-Ext4Engine::~Ext4Engine()
-{
-}
-
-void Ext4Engine::mount(const Ext4Engine::data& key, unsigned int options)
-{
- addKey(key);
- /* mount : /dev/mmcblk0p21 /opt/usr_encrypt */
- if (::mount(source.c_str(), secondMountPoint.c_str(), "ext4", 0, 0) < 0)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- /* bind mount :/opt/usr_encrypt/secure /opt/usr */
- if (::mount(bindMountPoint.c_str(), destination.c_str(), "ext4", MS_BIND, 0) < 0)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-}
-
-void Ext4Engine::umount()
-{
- /* for decrypt, umount /opt/usr */
- if (::umount(destination.c_str()))
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-}
-
-void Ext4Engine::addKey(const Ext4Engine::data& key)
-{
- addKeyToKeyring(key);
-}
-
-void Ext4Engine::encrypt(const Ext4Engine::data& key, unsigned int options)
-{
- std::string sourceDir = getSource();
- std::string destDir = getDestination();
- bool copyFlag = false;
-
- if (!(copyFlag = prepareEncryptDir(sourceDir, destDir)))
- throw runtime::Exception("prepareEncryptDir failed");
-
- preScanDir(secondMountPoint);
- /* key add to keyring */
- addKeyToKeyring(key);
- /* set policy */
- setPolicy(bindMountPoint, key);
-
- if (copyFlag)
- listDir(secondMountPoint, bindMountPoint, true);
- INFO("[ext4 encrypt] copy done");
-
- progressBar.done();
- if (::mount(bindMountPoint.c_str(), destDir.c_str(), "ext4", MS_BIND, 0) < 0)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-}
-
-void Ext4Engine::decrypt(const Ext4Engine::data& key, unsigned int options)
-{
- std::string destDir = getDestination();
-
- if (!getPolicy(bindMountPoint))
- throw runtime::Exception("directory isn't encrypted");
- addKeyToKeyring(key);
-
- preScanDir(bindMountPoint);
-
- listDir(bindMountPoint, secondMountPoint, false);
- INFO("[ext4 decrypt] copy done");
- progressBar.done();
-
- if (::open(bindMountPoint.c_str(), O_RDONLY) != -1)
- ::remove(bindMountPoint.c_str());
-
- /* umount /opt/usr_encrypt */
- if (::umount(secondMountPoint.c_str()))
- throw runtime::Exception(runtime::GetSystemErrorMessage());
- /* mount /dev/mmcblk0p21 /opt/usr */
- if (::mount(source.c_str(), destination.c_str(), "ext4", 0, 0) < 0)
- throw runtime::Exception(runtime::GetSystemErrorMessage());
-
- if (::open(secondMountPoint.c_str(), O_RDONLY) != -1)
- ::remove(secondMountPoint.c_str());
-}
-
-bool Ext4Engine::isKeyMetaSet()
-{
- return FileFooter::exist(source);
-}
-
-const Ext4Engine::data Ext4Engine::getKeyMeta()
-{
- return FileFooter::read(source);
-}
-
-void Ext4Engine::setKeyMeta(const data &data)
-{
- FileFooter::write(source, data);
-}
-
-void Ext4Engine::clearKeyMeta()
-{
- FileFooter::clear(source);
-}
-
-unsigned int Ext4Engine::getSupportedOptions()
-{
- return 0;
-}
-
-} // namespace ode
+++ /dev/null
-/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-#ifndef __EXT4_ENGINE_H__
-#define __EXT4_ENGINE_H__
-
-#include <vector>
-#include <string>
-
-#include "progress-bar.h"
-
-namespace ode {
-
-class Ext4Engine final {
-public:
- Ext4Engine(const std::string& src, const std::string& dest, const ProgressBar &prgsBar);
- Ext4Engine(const Ext4Engine&) = delete;
- Ext4Engine(Ext4Engine&&) = delete;
- ~Ext4Engine();
-
- Ext4Engine& operator=(const Ext4Engine&) = delete;
- Ext4Engine& operator=(Ext4Engine&&) = delete;
-
- const std::string& getSource()
- {
- return source;
- }
-
- const std::string& getDestination()
- {
- return destination;
- }
-
- typedef std::vector<unsigned char> data;
-
- void mount(const data &key, unsigned int options);
- void umount();
-
- void addKey(const data &key);
- void encrypt(const data &key, unsigned int options);
- void decrypt(const data &key, unsigned int options);
-
- bool isKeyMetaSet();
- const data getKeyMeta();
- void setKeyMeta(const data &data);
- void clearKeyMeta();
-
- unsigned int getSupportedOptions();
-
- int copy(std::string& src, std::string& dest);
- void listDir(std::string& source, std::string& dest, bool excludeFlag);
-
-private:
- std::string source, destination;
- ProgressBar progressBar;
-};
-
-} // namespace ode
-#endif // __EXT4_ENGINE_H__
#include "launchpad.h"
#include "app-bundle.h"
#include "progress-bar.h"
-#include "engine/ecryptfs-engine.h"
+#include "engine/encryption/ecryptfs-engine.h"
#include "key-manager/key-manager.h"
#include "rmi/external-encryption.h"
#include "vconf.h"
#include "progress-bar.h"
-#include "engine/dmcrypt-engine.h"
+#include "engine/encryption/dmcrypt-engine.h"
#include "key-manager/key-manager.h"
#include "rmi/internal-encryption.h"
* limitations under the License
*/
#include <fstream>
-
-#include <stdio.h>
-#include <unistd.h>
-#include <linux/fs.h>
-#include <linux/fiemap.h>
-
#include <vconf.h>
-#include <klay/exception.h>
-#include <klay/filesystem.h>
-#include <klay/audit/logger.h>
+#include <unistd.h>
-#include "ext4-tool.h"
-#include "block-device.h"
-#include "progress-bar.h"
+#include "engine/erase/mmc-engine.h"
#include "rmi/secure-erase.h"
+#define ERASE_ENGINE MMCEraseEngine
#define PRIVILEGE_PLATFORM "http://tizen.org/privilege/internal/default/platform"
namespace ode {
namespace {
-std::unique_ptr<ProgressBar> progressBar;
+std::unique_ptr<ERASE_ENGINE> engine;
-static int totalFileCount = 0;
-static int erasedFileCount = 0;
-
-static int getTotalFileCount(const std::string &name)
+void dropCachePage(void)
{
- int total = 0;
- runtime::DirectoryIterator iter(name), end;
-
- while (iter != end) {
- std::string next = name + "/" + iter->getName();
- runtime::File file(next);
- if (!file.exists()) {
- return -1;
- }
-
- if (file.isFile()) {
- total++;
- } else if (file.isDirectory()) {
- int subTotal = getTotalFileCount(next);
- if (subTotal != -1)
- total += subTotal;
- }
- ++iter;
+ std::ofstream file;
+
+ file.open("/proc/sys/vm/drop_caches");
+ if (file.fail()) {
+ throw runtime::Exception("failed to access drop_caches file");
}
- return total;
+ file << "3\n";
+ file.close();
+ ::sync();
+ return;
}
} /* namespace */
SecureErase::SecureErase(ODEControlContext &ctx) :
- context(ctx), devicePath("")
+ context(ctx)
{
context.expose(this, PRIVILEGE_PLATFORM, (int)(SecureErase::erase)(std::string));
context.expose(this, PRIVILEGE_PLATFORM, (int)(SecureErase::clean)(std::string));
- progressBar.reset(new ProgressBar([](int v) {
- ::vconf_set_str(VCONFKEY_ODE_ERASE_PROGRESS, std::to_string(v).c_str());
- }));
+ engine.reset(new ERASE_ENGINE(ProgressBar([](int v) {
+ ::vconf_set_str(VCONFKEY_ODE_ERASE_PROGRESS, std::to_string(v).c_str());
+ }))
+ );
}
SecureErase::~SecureErase()
auto eraseWorker = [name, this]() {
try {
runtime::File file(name);
-
- BlockDevice blockDevice(name);
- devicePath = blockDevice.getName();
-
- if (file.isFile()) {
- totalFileCount = 1;
- fileErase(name);
- } else if (file.isDirectory()) {
- totalFileCount = getTotalFileCount(name);
- erasedFileCount = 0;
- directoryErase(name);
- } else if (file.isDevice()) {
- Ext4Tool ext4Tool(name);
- unsigned int totalBlock = ext4Tool.getTotalBlockCount();
- unsigned int blockSize = (unsigned int)blockDevice.getSize();
-
- for (unsigned int i = 0; i < totalBlock; i++) {
- Block block(i * blockSize, blockSize);
- blockDevice.discard(block);
- progressBar->update(i, totalBlock, 1);
- }
+ if (file.isDevice()) {
+ engine->eraseDevice(name);
+ } else {
+ engine->eraseFiles(name);
}
dropCachePage();
- progressBar->done();
} catch (runtime::Exception &e) {}
};
int SecureErase::clean(const std::string &name)
{
- try {
- runtime::File file(name, O_WRONLY);
- if (!file.exists() || !file.isDevice())
- return -1;
- } catch (runtime::Exception &e) {}
-
auto cleanWorker = [name, this]() {
try {
- BlockDevice blockDevice(name);
- unsigned totalBlock, blockSize;
-
- Ext4Tool ext4Tool(name);
- totalBlock = ext4Tool.getTotalBlockCount();
- blockSize = (unsigned int) blockDevice.getSize();
-
- for (unsigned int i = 0; i < totalBlock; i++) {
- if (!ext4Tool.isUsedBlock(i)) {
- Block block(i * blockSize, blockSize);
- blockDevice.discard(block);
- }
-
- progressBar->update(i, totalBlock, 1);
- }
+ engine->cleanDevice(name);
dropCachePage();
- progressBar->done();
} catch (runtime::Exception &e) {}
};
std::thread asyncWork(cleanWorker);
asyncWork.detach();
-
- return 0;
-}
-
-int SecureErase::fileErase(const std::string &name)
-{
- int ret = 0, fd = 0;
- int extentBlockCount = 0;
- char buf[4096] = "";
- struct fiemap *fmap = (struct fiemap *)buf;
- struct fiemap_extent *fm_ext = NULL;
- int count = (sizeof(buf) - sizeof(*fmap)) / sizeof(struct fiemap_extent);
-
- /* [TBD] stop the related process */
-
- BlockDevice blockDevice(devicePath);
-
- ::memset(fmap, 0, sizeof(struct fiemap));
-
- fd = ::open(name.c_str(), O_RDONLY);
- if (fd < 0) {
- return -1;
- }
-
- fmap->fm_length = ~0ULL;
- fmap->fm_flags = 0;
- fmap->fm_extent_count = count;
-
- ret = ::ioctl(fd, FS_IOC_FIEMAP, (unsigned long)fmap);
- if (ret < 0) {
- ::close(fd);
- return -1;
- }
-
- ::close(fd);
-
- fm_ext = &fmap->fm_extents[0];
- extentBlockCount = (int)fmap->fm_mapped_extents;
-
- for (int i = 0; i < extentBlockCount; i++) {
- Block block(fm_ext[i].fe_physical, fm_ext[i].fe_length);
- ret = blockDevice.secDiscard(block);
- if (ret < 0) {
- return -1;
- }
-
- if (totalFileCount == 1) {
- progressBar->update(i, extentBlockCount, 1);
- }
- }
-
- return ret;
-}
-
-int SecureErase::directoryErase(const std::string &name)
-{
- runtime::DirectoryIterator iter(name), end;
- while (iter != end) {
- std::string next = name + "/" + iter->getName();
- runtime::File file(next);
- if (!file.exists()) {
- return -1;
- }
-
- if (file.isFile()) {
- fileErase(next);
- ::remove(next.c_str());
- erasedFileCount++;
- progressBar->update(erasedFileCount, totalFileCount, 1);
- } else if (file.isDirectory()) {
- directoryErase(next);
- }
- ++iter;
- }
-
- fileErase(name);
- ::rmdir(name.c_str());
return 0;
}
-void SecureErase::dropCachePage()
-{
- std::ofstream file;
-
- file.open("/proc/sys/vm/drop_caches");
- if (file.fail()) {
- throw runtime::Exception("Failed to access drop_caches file");
- }
- file << "3\n";
- file.close();
- ::sync();
-
- return;
-}
-
} // namespace ode
af.cpp
../server/file-footer.cpp
../server/kernel-keyring.cpp
- ../server/engine/ext4-engine.cpp
- ../server/engine/ecryptfs-engine.cpp
+ ../server/engine/encryption/ext4-engine.cpp
+ ../server/engine/encryption/ecryptfs-engine.cpp
../server/key-manager/key-generator.cpp
../server/key-manager/anti-forensics.cpp
../server/ext4-tool.cpp
#include <klay/testbench.h>
#include <klay/process.h>
-#include "../server/engine/dmcrypt-engine.cpp"
+#include "../server/engine/encryption/dmcrypt-engine.cpp"
#define TEST_USERDATA_NAME "userdata"
#define TEST_USERDATA_PATH "/opt/usr"
#include <klay/exception.h>
#include <klay/testbench.h>
-#include "../server/engine/ecryptfs-engine.h"
+#include "../server/engine/encryption/ecryptfs-engine.h"
#define TEST_PATH "/opt/usr"
#include <klay/exception.h>
#include <klay/testbench.h>
-#include "../server/engine/ext4-engine.h"
+#include "../server/engine/encryption/ext4-engine.h"
#define TEST_PATH "/opt/usr"