Refactor secure erase and add MMC erase engine 83/114183/4
authorseolheui,kim <s414.kim@samsung.com>
Fri, 10 Feb 2017 08:26:35 +0000 (17:26 +0900)
committerseolheui,kim <s414.kim@samsung.com>
Fri, 10 Feb 2017 08:58:22 +0000 (17:58 +0900)
Change-Id: Ibfd5df003e1ec10ee2e1a34107eb341a7501f7c7
Signed-off-by: seolheui,kim <s414.kim@samsung.com>
23 files changed:
rmi/secure-erase.h
server/CMakeLists.txt
server/engine/dmcrypt-engine.cpp [deleted file]
server/engine/dmcrypt-engine.h [deleted file]
server/engine/ecryptfs-engine.cpp [deleted file]
server/engine/ecryptfs-engine.h [deleted file]
server/engine/encryption/dmcrypt-engine.cpp [new file with mode: 0644]
server/engine/encryption/dmcrypt-engine.h [new file with mode: 0644]
server/engine/encryption/ecryptfs-engine.cpp [new file with mode: 0644]
server/engine/encryption/ecryptfs-engine.h [new file with mode: 0644]
server/engine/encryption/ext4-engine.cpp [new file with mode: 0644]
server/engine/encryption/ext4-engine.h [new file with mode: 0644]
server/engine/erase/mmc-engine.cpp [new file with mode: 0644]
server/engine/erase/mmc-engine.h [new file with mode: 0644]
server/engine/ext4-engine.cpp [deleted file]
server/engine/ext4-engine.h [deleted file]
server/external-encryption.cpp
server/internal-encryption.cpp
server/secure-erase.cpp
tests/CMakeLists.txt
tests/dmcrypt-engine.cpp
tests/ecryptfs-engine.cpp
tests/ext4-engine.cpp

index 48facda12124a3029f5a838fbe75473be96449a5..2eb47356dcaacfaf1f5ca83f6141cd6f8c891d81 100644 (file)
@@ -33,13 +33,8 @@ public:
        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
index 6ec742ae065b7f52f0f2d91d7e1b863ce16e2368..c07f9e15cb71341013afae2fdc3e54eae15207fc 100644 (file)
@@ -25,9 +25,10 @@ SET(SERVER_SRCS      main.cpp
                                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
diff --git a/server/engine/dmcrypt-engine.cpp b/server/engine/dmcrypt-engine.cpp
deleted file mode 100644 (file)
index 8152d76..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- *  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
diff --git a/server/engine/dmcrypt-engine.h b/server/engine/dmcrypt-engine.h
deleted file mode 100644 (file)
index 8f71f44..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *  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__
diff --git a/server/engine/ecryptfs-engine.cpp b/server/engine/ecryptfs-engine.cpp
deleted file mode 100644 (file)
index cea2716..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- *  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;
-                                       },
-                                       [&current, &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,
-                                       [&current, &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
diff --git a/server/engine/ecryptfs-engine.h b/server/engine/ecryptfs-engine.h
deleted file mode 100644 (file)
index 4a57f1f..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  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__
-
diff --git a/server/engine/encryption/dmcrypt-engine.cpp b/server/engine/encryption/dmcrypt-engine.cpp
new file mode 100644 (file)
index 0000000..ce97023
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ *  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
diff --git a/server/engine/encryption/dmcrypt-engine.h b/server/engine/encryption/dmcrypt-engine.h
new file mode 100644 (file)
index 0000000..8f71f44
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  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__
diff --git a/server/engine/encryption/ecryptfs-engine.cpp b/server/engine/encryption/ecryptfs-engine.cpp
new file mode 100644 (file)
index 0000000..ece06ad
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ *  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;
+                                       },
+                                       [&current, &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,
+                                       [&current, &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
diff --git a/server/engine/encryption/ecryptfs-engine.h b/server/engine/encryption/ecryptfs-engine.h
new file mode 100644 (file)
index 0000000..983ed6d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  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__
+
diff --git a/server/engine/encryption/ext4-engine.cpp b/server/engine/encryption/ext4-engine.cpp
new file mode 100644 (file)
index 0000000..0abd19c
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ *  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
diff --git a/server/engine/encryption/ext4-engine.h b/server/engine/encryption/ext4-engine.h
new file mode 100644 (file)
index 0000000..eb233f4
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  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__
diff --git a/server/engine/erase/mmc-engine.cpp b/server/engine/erase/mmc-engine.cpp
new file mode 100644 (file)
index 0000000..f9d84c6
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *  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 */
diff --git a/server/engine/erase/mmc-engine.h b/server/engine/erase/mmc-engine.h
new file mode 100644 (file)
index 0000000..31990a0
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  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__*/
diff --git a/server/engine/ext4-engine.cpp b/server/engine/ext4-engine.cpp
deleted file mode 100644 (file)
index e04801a..0000000
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- *  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
diff --git a/server/engine/ext4-engine.h b/server/engine/ext4-engine.h
deleted file mode 100644 (file)
index eb233f4..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  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__
index 79001d38e8d2a38ccb9a1c43dc805cbe4019177a..173323ae191c9c0a7fd8b720a46e6e0857537c48 100644 (file)
@@ -33,7 +33,7 @@
 #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"
index 284e436b14c19d4c1b6233ec7e9da9578f7fe8ff..f294f20b402e29d8d5d0d9f79388bf523d9f4cb1 100644 (file)
@@ -29,7 +29,7 @@
 
 #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"
index e8b66ad64e97b18408b076772b602fec92aa89fd..2a46a256158936e39b7d458d37772d97fe5021d8 100644 (file)
  *  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()
@@ -88,30 +67,12 @@ int SecureErase::erase(const std::string &name)
        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) {}
        };
 
@@ -123,129 +84,16 @@ int SecureErase::erase(const std::string &name)
 
 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
index b7b8bc5666a889c11a2c4babc8e5a74102f15480..a9d1c08c5927f03e45a84e7e3639e81e974d6fcf 100755 (executable)
@@ -22,8 +22,8 @@ SET(TEST_SRC  main.cpp
                                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
index 7fecdedd0b8f8c3b7aade1c2d25d99fa97689259..e5ff64425e03d931a338db9a206b4ff188618816 100644 (file)
@@ -29,7 +29,7 @@
 #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"
index a35f83e5834de350f2ba58db53f8a374c77541bc..6d136313c175b1ace934b3cc672e7f03bbd30afa 100644 (file)
@@ -18,7 +18,7 @@
 #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"
 
index 9e89612072022190b0dcffc9ae4cbf8d61b1d1c1..d0efba5a3422fdba9c02e22f321aea594adb84b5 100755 (executable)
@@ -18,7 +18,7 @@
 #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"