--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include "cryptsetup-engine.h"
+#include "../../file-footer.h"
+
+#include <cctype>
+#include <algorithm>
+
+#include <libcryptsetup.h>
+
+#include <klay/exception.h>
+#include <klay/audit/logger.h>
+
+namespace ode {
+
+namespace {
+
+const char* DEFAULT_LUKS_CIPHER_NAME = "aes";
+const char* DEFAULT_LUKS_CIPHER_MODE = "xts-plain64";
+const char* DEFAULT_LUKS_HASH = "sha1";
+const size_t DEFAULT_LUKS_ALIGNMENT = 0;
+
+#ifndef NDEBUG
+// log callback
+void log(int level, const char *msg, void*)
+{
+ std::string msgStr("[NULL]");
+ if (msg) {
+ msgStr = msg;
+
+ // trim it
+ auto it = find_if_not(msgStr.rbegin(),
+ msgStr.rend(),
+ [](char c){ return isspace(c); }).base();
+ msgStr.erase(it, msgStr.end());
+ }
+
+ switch (level)
+ {
+ case CRYPT_LOG_ERROR:
+ ERROR("[libcryptsetup] " + msgStr);
+ break;
+ case CRYPT_LOG_VERBOSE:
+ INFO("[libcryptsetup] " + msgStr);
+ break;
+ case CRYPT_LOG_DEBUG:
+ case CRYPT_LOG_NORMAL:
+ DEBUG("[libcryptsetup] " + msgStr);
+ break;
+ default:
+ ERROR("[libcryptsetup] Unsupported log level. Msg: " + msgStr);
+ }
+}
+#endif
+
+class Device
+{
+public:
+ enum class InitMethod
+ {
+ BY_DEV_PATH, // requires device path as first ctor argument
+ BY_MAP_NAME, // requires mapping name as first ctor argument
+ };
+
+ explicit Device(const std::string &str, InitMethod method = InitMethod::BY_DEV_PATH)
+ {
+ int ret;
+ if (str.empty())
+ throw runtime::Exception("Empty argument");
+
+ switch (method) {
+ case InitMethod::BY_DEV_PATH:
+ ret = crypt_init(&device, str.c_str());
+ if (ret != 0)
+ throw runtime::Exception("crypt_init() failed for " + str + ": "
+ + std::to_string(ret));
+ break;
+ case InitMethod::BY_MAP_NAME:
+ ret = crypt_init_by_name(&device, str.c_str());
+ if (ret != 0)
+ throw runtime::Exception("crypt_init_by_name() failed for " +
+ str + ": " + std::to_string(ret));
+ break;
+ default:
+ throw runtime::Exception("Unsupported init method " +
+ std::to_string(static_cast<int>(method)));
+ }
+
+#ifndef NDEBUG
+ /*
+ * This option causes debug logs to be printed to STDOUT. TODO execute it
+ * once for all engines?
+ */
+ crypt_set_debug_level(CRYPT_DEBUG_ALL);
+ crypt_set_log_callback(device, &log, NULL);
+#endif
+
+ // Needs root
+ if (1 != crypt_memory_lock(device, 1))
+ throw runtime::Exception("Failed to lock memory");
+ }
+
+ Device(const Device&) = delete;
+ Device& operator=(const Device&) = delete;
+
+ ~Device()
+ {
+ if (0 != crypt_memory_lock(device, 0))
+ ERROR("Failed to unlock memory");
+
+ crypt_free(device);
+ }
+
+ crypt_device* get() noexcept { return device; }
+
+private:
+ crypt_device *device;
+};
+
+std::string mappingPath(const std::string& name)
+{
+ static std::string mappings_dir = std::string(crypt_get_dir()) + '/';
+ return mappings_dir + name;
+}
+
+} // anonymous namespace
+
+
+CryptsetupEngine::CryptsetupEngine(const std::string &devicePath) :
+ devPath(devicePath)
+{
+}
+
+CryptsetupEngine::~CryptsetupEngine()
+{
+}
+
+void CryptsetupEngine::format(DeviceType type, const data &key)
+{
+ switch (type) {
+ case DeviceType::LUKS:
+ {
+ Device d(devPath);
+
+ // TODO support other formats? support other ciphers?
+ crypt_params_luks1 params = {
+ .hash = DEFAULT_LUKS_HASH,
+ .data_alignment = DEFAULT_LUKS_ALIGNMENT,
+ .data_device = NULL,
+ };
+
+ int ret = crypt_format(d.get(),
+ CRYPT_LUKS1,
+ DEFAULT_LUKS_CIPHER_NAME,
+ DEFAULT_LUKS_CIPHER_MODE,
+ NULL, // NULL uid
+ reinterpret_cast<const char*>(key.data()),
+ key.size(),
+ ¶ms);
+ if (ret != 0)
+ throw runtime::Exception("crypt_format() failed: " + std::to_string(ret));
+ break;
+ }
+ case DeviceType::PLAIN:
+ // TODO
+ default:
+ throw runtime::Exception("Unsupported device type " +
+ std::to_string(static_cast<int>(type)));
+ }
+}
+
+std::string CryptsetupEngine::open(DeviceType type, const std::string &name, const data &key)
+{
+ // create new mapping
+ switch (type) {
+ case DeviceType::LUKS:
+ {
+ Device d(devPath);
+ int ret = crypt_load(d.get(), CRYPT_LUKS1, NULL);
+ if (ret != 0)
+ throw runtime::Exception("crypt_load() failed: " + std::to_string(ret));
+
+ // TODO possible support for activation flags
+ ret = crypt_activate_by_volume_key(d.get(),
+ name.c_str(),
+ reinterpret_cast<const char*>(key.data()),
+ key.size(),
+ 0);
+ if (ret != 0)
+ throw runtime::Exception("crypt_activate_by_volume_key() failed: " +
+ std::to_string(ret));
+ break;
+ }
+
+ case DeviceType::PLAIN:
+ // TODO
+ default:
+ throw runtime::Exception("Unsupported device type " +
+ std::to_string(static_cast<int>(type)));
+ }
+ return mappingPath(name);
+}
+
+void CryptsetupEngine::close(const std::string &name)
+{
+ Device d(name, Device::InitMethod::BY_MAP_NAME);
+
+ int ret = crypt_deactivate(d.get(), name.c_str());
+ if (ret != 0)
+ throw runtime::Exception("crypt_deactivate() failed for " + name +
+ ": " + std::to_string(ret));
+}
+
+bool CryptsetupEngine::isKeyMetaSet()
+{
+ return FileFooter::exist(devPath);
+}
+
+const CryptsetupEngine::data CryptsetupEngine::getKeyMeta()
+{
+ return FileFooter::read(devPath);
+}
+
+void CryptsetupEngine::setKeyMeta(const data &meta)
+{
+ FileFooter::write(devPath, meta);
+}
+
+void CryptsetupEngine::clearKeyMeta()
+{
+ FileFooter::clear(devPath);
+}
+
+} // namespace ode
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#ifndef __CRYPTSETUP_ENGINE_H__
+#define __CRYPTSETUP_ENGINE_H__
+
+#include <string>
+#include <vector>
+
+namespace ode {
+
+class CryptsetupEngine final {
+public:
+ enum class DeviceType {
+ PLAIN,
+ LUKS,
+ };
+
+ CryptsetupEngine(const std::string &devicePath);
+ CryptsetupEngine(const CryptsetupEngine &) = delete;
+ CryptsetupEngine(CryptsetupEngine &&) = delete;
+ ~CryptsetupEngine();
+
+ CryptsetupEngine &operator=(const CryptsetupEngine &) = delete;
+ CryptsetupEngine &operator=(CryptsetupEngine &&) = delete;
+
+ // TODO make it common among engines
+ typedef std::vector<unsigned char> data;
+
+ void format(DeviceType type, const data &key);
+
+ // create new mapping, returns mapping path
+ std::string open(DeviceType type, const std::string &name, const data &key);
+
+ static void close(const std::string &name);
+
+ bool isKeyMetaSet();
+ const data getKeyMeta();
+ void setKeyMeta(const data &data);
+ void clearKeyMeta();
+
+private:
+ std::string devPath;
+};
+
+} // namespace ode
+#endif // __CRYPTSETUP_ENGINE_H__