2 * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
17 #include "cryptsetup-engine.h"
18 #include "../../file-footer.h"
19 #include "../../logger.h"
24 #include <libcryptsetup.h>
26 #include <klay/exception.h>
32 const char* DEFAULT_LUKS_CIPHER_NAME = "aes";
33 const char* DEFAULT_LUKS_CIPHER_MODE = "xts-plain64";
34 const char* DEFAULT_LUKS_HASH = "sha1";
35 const size_t DEFAULT_LUKS_ALIGNMENT = 0;
39 void log(int level, const char *msg, void*)
41 std::string msgStr("[NULL]");
46 auto it = find_if_not(msgStr.rbegin(),
48 [](char c){ return isspace(c); }).base();
49 msgStr.erase(it, msgStr.end());
55 ERROR(SINK, "[libcryptsetup] " + msgStr);
57 case CRYPT_LOG_VERBOSE:
58 INFO(SINK, "[libcryptsetup] " + msgStr);
61 case CRYPT_LOG_NORMAL:
62 DEBUG(SINK, "[libcryptsetup] " + msgStr);
65 ERROR(SINK, "[libcryptsetup] Unsupported log level. Msg: " + msgStr);
75 BY_DEV_PATH, // requires device path as first ctor argument
76 BY_MAP_NAME, // requires mapping name as first ctor argument
79 explicit Device(const std::string &str, InitMethod method = InitMethod::BY_DEV_PATH)
83 throw runtime::Exception("Empty argument");
86 case InitMethod::BY_DEV_PATH:
87 ret = crypt_init(&device, str.c_str());
89 throw runtime::Exception("crypt_init() failed for " + str + ": "
90 + std::to_string(ret));
92 case InitMethod::BY_MAP_NAME:
93 ret = crypt_init_by_name(&device, str.c_str());
95 throw runtime::Exception("crypt_init_by_name() failed for " +
96 str + ": " + std::to_string(ret));
99 throw runtime::Exception("Unsupported init method " +
100 std::to_string(static_cast<int>(method)));
105 * This option causes debug logs to be printed to STDOUT. TODO execute it
106 * once for all engines?
108 crypt_set_debug_level(CRYPT_DEBUG_ALL);
109 crypt_set_log_callback(device, &log, NULL);
113 if (1 != crypt_memory_lock(device, 1))
114 throw runtime::Exception("Failed to lock memory");
117 Device(const Device&) = delete;
118 Device& operator=(const Device&) = delete;
122 if (0 != crypt_memory_lock(device, 0))
123 ERROR(SINK, "Failed to unlock memory");
128 crypt_device* get() noexcept { return device; }
131 crypt_device *device;
134 std::string mappingPath(const std::string& name)
136 static std::string mappings_dir = std::string(crypt_get_dir()) + '/';
137 return mappings_dir + name;
140 } // anonymous namespace
143 CryptsetupEngine::CryptsetupEngine(const std::string &devicePath) :
148 CryptsetupEngine::~CryptsetupEngine()
152 void CryptsetupEngine::format(DeviceType type, const data &key)
155 case DeviceType::LUKS:
159 // TODO support other formats? support other ciphers?
160 crypt_params_luks1 params = {
161 .hash = DEFAULT_LUKS_HASH,
162 .data_alignment = DEFAULT_LUKS_ALIGNMENT,
166 int ret = crypt_format(d.get(),
168 DEFAULT_LUKS_CIPHER_NAME,
169 DEFAULT_LUKS_CIPHER_MODE,
171 reinterpret_cast<const char*>(key.data()),
175 throw runtime::Exception("crypt_format() failed: " + std::to_string(ret));
178 case DeviceType::PLAIN:
181 throw runtime::Exception("Unsupported device type " +
182 std::to_string(static_cast<int>(type)));
186 std::string CryptsetupEngine::open(DeviceType type, const std::string &name, const data &key)
188 // create new mapping
190 case DeviceType::LUKS:
193 int ret = crypt_load(d.get(), CRYPT_LUKS1, NULL);
195 throw runtime::Exception("crypt_load() failed: " + std::to_string(ret));
197 // TODO possible support for activation flags
198 ret = crypt_activate_by_volume_key(d.get(),
200 reinterpret_cast<const char*>(key.data()),
204 throw runtime::Exception("crypt_activate_by_volume_key() failed: " +
205 std::to_string(ret));
209 case DeviceType::PLAIN:
212 throw runtime::Exception("Unsupported device type " +
213 std::to_string(static_cast<int>(type)));
215 return mappingPath(name);
218 void CryptsetupEngine::close(const std::string &name)
220 Device d(name, Device::InitMethod::BY_MAP_NAME);
222 int ret = crypt_deactivate(d.get(), name.c_str());
224 throw runtime::Exception("crypt_deactivate() failed for " + name +
225 ": " + std::to_string(ret));
228 bool CryptsetupEngine::isKeyMetaSet()
230 return FileFooter::exist(devPath);
233 const CryptsetupEngine::data CryptsetupEngine::getKeyMeta()
235 return FileFooter::read(devPath);
238 void CryptsetupEngine::setKeyMeta(const data &meta)
240 FileFooter::write(devPath, meta);
243 void CryptsetupEngine::clearKeyMeta()
245 FileFooter::clear(devPath);