2 * Copyright (c) 2015 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.
20 * @brief CLI tool to encrypt/decrypt storage and secure erase
30 #include <condition_variable>
33 #include <ode/secure-erase.h>
34 #include <ode/internal-encryption.h>
35 #include <ode/external-encryption.h>
39 extern char** environ;
42 bool mountFlag = false;
44 static inline int usage(const std::string name)
46 std::cout << "Usage: " << name << " [Option]" << std::endl
48 << "Options :" << std::endl
49 << " -m, --mount=internal|external mount" << std::endl
50 << " -u, --umount=internal|external umount" << std::endl
51 << " -e, --encrypt=internal|external encrypt" << std::endl
52 << " -d, --decrypt=internal|external decrypt" << std::endl
53 << " -l --luks=format|open|close|wait perform LUKS operation using asynchronous" << std::endl
54 << " API or wait for completion. May also" << std::endl
55 << " require -D and/or -M option." << std::endl
56 << " -L --luks_sync=format|open|close perform LUKS operation using synchronous" << std::endl
57 << " API. May also require -D and/or -M option." << std::endl
58 << " -D --device=<device> device path" << std::endl
59 << " -M --mapping=<mapping> mapping name required for LUKS open and" << std::endl
60 << " LUKS close operations" << std::endl
61 << " -k, --keys=store|remove Store/remove the master key of given device" << std::endl
62 << " for the purpose of system upgrade. Requires" << std::endl
63 << " -D option" << std::endl
64 << " -p, --changepw=internal|external change password" << std::endl
65 << " -s, --state=internal|external get state" << std::endl
66 << " -w, --waitmnt=internal|external wait for mount"<< std::endl
67 << " -c, --clean=DIRECTORY secure-clean" << std::endl
68 << " -r, --recovery=internal|external recovery" << std::endl
69 << " -h, --help show this" << std::endl
75 static inline std::string getPassword() {
78 std::cout << "Password: ";
81 tcgetattr(STDIN_FILENO, &oldt);
84 newt.c_lflag &= ~ECHO;
85 tcsetattr(STDIN_FILENO, TCSANOW, &newt);
89 tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
90 std::cout << std::endl;
95 static inline void printSelectableStorage(bool internal = true,
98 bool firstDone = false;
99 std::cerr << "Just choose one among followings :" << std::endl;
102 std::cerr << "internal";
109 std::cerr << "external";
113 std::cerr << std::endl;
116 static inline int mount(const std::string name)
120 if (name == "internal") {
121 std::string password = getPassword();
122 ret = ode_internal_encryption_set_mount_password(password.c_str());
124 ret = ode_internal_encryption_mount();
126 std::cerr << "Password setting failed" << std::endl;
128 } else if (name == "external") {
129 std::string password = getPassword();
130 ret = ode_external_encryption_set_mount_password(password.c_str());
132 ret = ode_external_encryption_mount();
134 std::cerr << "Password setting failed" << std::endl;
137 printSelectableStorage();
142 std::cerr << "Error : " << ret <<std::endl;
148 static inline int umount(const std::string name)
152 if (name == "internal") {
153 ret = ode_internal_encryption_umount();
154 } else if (name == "external") {
155 ret = ode_external_encryption_umount();
157 printSelectableStorage();
162 std::cerr << "Error : " << ret <<std::endl;
168 static inline int encrypt_storage(const std::string name)
172 if (name == "internal") {
174 ode_internal_encryption_is_password_initialized(&result);
178 std::string password = getPassword();
179 ode_internal_encryption_init_password(password.c_str());
183 std::cout << "Confirm ";
184 std::string password = getPassword();
185 ode_internal_encryption_verify_password(password.c_str(), &result);
188 std::cerr << "Confirm password doesn't match" << std::endl;
192 unsigned int options = 0;
193 ode_internal_encryption_get_supported_options(&options);
196 if (options & ODE_OPTION_INTERNAL_INCLUDE_UNUSED_REGION) {
197 std::cout << "Encrypt All (include unused region)? (y/n) ";
199 if (answer != 'Y' && answer != 'y') {
200 options &= ~ODE_OPTION_INTERNAL_INCLUDE_UNUSED_REGION;
203 ret = ode_internal_encryption_encrypt(password.c_str(), options);
204 } else if (name == "external") {
206 ode_external_encryption_is_password_initialized(&result);
210 std::string password = getPassword();
211 ode_external_encryption_init_password(password.c_str());
215 std::cout << "Confirm ";
216 std::string password = getPassword();
217 ode_external_encryption_verify_password(password.c_str(), &result);
220 std::cerr << "Confirm password doesn't match" << std::endl;
224 unsigned int options;
225 ode_external_encryption_get_supported_options(&options);
228 if (options & ODE_OPTION_EXTERNAL_ONLY_NEW_FILE) {
229 std::cout << "Encrypt new files only? (y/n) ";
231 if (answer != 'Y' && answer != 'y') {
232 options &= ~ODE_OPTION_EXTERNAL_ONLY_NEW_FILE;
235 if (options & ODE_OPTION_EXTERNAL_EXCEPT_FOR_MEDIA_FILE) {
236 std::cout << "Encrypt non-media files only? (y/n) ";
238 if (answer != 'Y' && answer != 'y') {
239 options &= ~ODE_OPTION_EXTERNAL_EXCEPT_FOR_MEDIA_FILE;
242 ret = ode_external_encryption_encrypt(password.c_str(), options);
244 printSelectableStorage(true, true);
249 std::cerr << "Error : " << ret <<std::endl;
255 static inline int decrypt_storage(const std::string name)
259 if (name == "internal") {
260 std::string password = getPassword();
261 ret = ode_internal_encryption_decrypt(password.c_str());
263 ode_internal_encryption_clean_password(password.c_str());
265 } else if (name == "external") {
266 std::string password = getPassword();
267 ret = ode_external_encryption_decrypt(password.c_str());
269 ode_external_encryption_clean_password(password.c_str());
272 printSelectableStorage(true, true);
277 std::cerr << "Error : " << ret <<std::endl;
285 explicit LuksWrapper(bool sync) : synchronous(sync) {
289 int ret = ode_luks_set_event_cb(&LuksWrapper::StaticCallback, this);
290 if (ret != ODE_ERROR_NONE)
291 throw std::runtime_error("Callback setting failed " + std::to_string(ret));
294 int format(const std::string& device)
297 std::string password = getPassword();
299 std::cout << "Confirm ";
300 std::string password2 = getPassword();
301 if (password != password2) {
302 std::cerr << "Confirm password doesn't match" << std::endl;
308 ret = ode_luks_format_sync(device.c_str(), password.c_str());
310 ret = ode_luks_format(device.c_str(), password.c_str());
312 if (ret != ODE_ERROR_NONE) {
313 std::cerr << "ode_luks_format() failed " << ret << std::endl;
319 return WaitForCallback(ODE_LUKS_FORMAT);
322 int open(const std::string& device, const std::string& mapping)
324 std::string password = getPassword();
327 ret = ode_luks_open_sync(device.c_str(), password.c_str(), mapping.c_str());
329 ret = ode_luks_open(device.c_str(), password.c_str(), mapping.c_str());
331 if (ret != ODE_ERROR_NONE) {
332 std::cerr << "ode_luks_open() failed " << ret << std::endl;
338 return WaitForCallback(ODE_LUKS_OPEN);
341 int close(const std::string& mapping)
345 ret = ode_luks_close_sync(mapping.c_str());
347 ret = ode_luks_close(mapping.c_str());
349 if (ret != ODE_ERROR_NONE) {
350 std::cerr << "ode_luks_close() failed " << ret << std::endl;
356 return WaitForCallback(ODE_LUKS_CLOSE);
361 return WaitForCallbackInternal([](ode_luks_operation_e) { return true; });
366 ode_luks_unset_event_cb();
370 static void StaticCallback(ode_luks_operation_e op, int ret, void* user_data)
372 auto self = static_cast<LuksWrapper*>(user_data);
373 self->Callback(op, ret);
376 void Callback(ode_luks_operation_e op, int ret)
379 std::lock_guard<std::mutex> guard(mutex);
380 results.push_back({op, ret});
385 int WaitForCallback(ode_luks_operation_e expected)
387 return WaitForCallbackInternal([=](ode_luks_operation_e op) {
388 return expected == op;
392 int WaitForCallbackInternal(const std::function<bool(ode_luks_operation_e)>& opCheck)
394 std::unique_lock<std::mutex> lock(mutex);
395 cond.wait(lock, [this]{
396 return !results.empty();
399 auto& res = results.front();
402 std::cout << "Luks callback received. Operation: " << static_cast<int>(res.op)
403 << " result: " << res.ret << std::endl;
404 if (!opCheck(res.op)) {
405 std::cerr << "Unexpected operation finished " << res.op << std::endl;
409 results.erase(results.begin());
415 std::condition_variable cond;
419 ode_luks_operation_e op;
423 std::vector<result> results;
427 static inline int luks(bool sync,
428 const std::string& name,
429 const std::string& device,
430 const std::string& mapping)
433 if (name == "format") {
437 LuksWrapper wrapper(sync);
438 return wrapper.format(device);
441 if (name == "open") {
442 if (device.empty() || mapping.empty())
445 LuksWrapper wrapper(sync);
446 return wrapper.open(device, mapping);
449 if (name == "close") {
453 LuksWrapper wrapper(sync);
454 return wrapper.close(mapping);
457 if (name == "wait" && !sync) {
458 LuksWrapper wrapper(sync);
459 return wrapper.wait();
463 std::cerr << "Wrong arguments (format|open|close)" << std::endl;
465 std::cerr << "Wrong arguments (format|open|close|wait)" << std::endl;
467 } catch (const std::runtime_error& e) {
468 std::cerr << e.what() << std::endl;
473 static inline int keys(const std::string& name, const std::string& device)
475 if (name == "store") {
479 std::string password = getPassword();
481 int ret = ode_key_store_master_key(device.c_str(), password.c_str());
482 if (ret != ODE_ERROR_NONE)
483 std::cerr << "Error : " << ret << std::endl;
487 if (name == "remove") {
491 int ret = ode_key_remove_master_key(device.c_str());
492 if (ret != ODE_ERROR_NONE)
493 std::cerr << "Error : " << ret << std::endl;
497 std::cerr << "Wrong arguments (store|remove)" << std::endl;
501 static inline int change_password(const std::string name)
506 std::string oldPW = getPassword();
509 std::string newPW = getPassword();
511 if (name == "internal") {
512 ret = ode_internal_encryption_change_password(oldPW.c_str(), newPW.c_str());
513 } else if (name == "external") {
514 ret = ode_external_encryption_change_password(oldPW.c_str(), newPW.c_str());
516 printSelectableStorage();
521 std::cerr << "Error : " << ret <<std::endl;
527 static inline int get_state(const std::string name)
531 if (name == "internal") {
532 ret = ode_internal_encryption_get_state(&state);
533 } else if (name == "external") {
534 ret = ode_external_encryption_get_state(&state);
536 printSelectableStorage();
541 std::cerr << "Error : " << ret <<std::endl;
546 case ODE_STATE_ENCRYPTED:
547 std::cout << "Encrypted";
549 case ODE_STATE_UNENCRYPTED:
550 std::cout << "Unencrypted";
552 case ODE_STATE_CORRUPTED:
553 std::cout << "Corrupted";
556 std::cout << "Invalid";
558 std::cout << std::endl;
563 static void mount_event_cb(void *user_data) {
564 std::unique_lock<std::mutex> lock(mtx);
565 std::condition_variable *pCond = (std::condition_variable*)user_data;
570 static inline int wait_for_mount(const std::string name)
573 std::unique_lock<std::mutex> lock(mtx);
574 std::condition_variable cond;
576 if (name == "internal") {
577 std::cout << "Wait for internal storage mount..." << std::endl;
578 ret = ode_internal_encryption_set_mount_event_cb(mount_event_cb, &cond);
579 } else if (name == "external") {
580 std::cout << "Wait for external storage mount..." << std::endl;
581 ret = ode_external_encryption_set_mount_event_cb(mount_event_cb, &cond);
583 printSelectableStorage();
588 std::cerr << "Error : " << ret <<std::endl;
592 cond.wait(lock, []{return mountFlag;});
593 std::cout << "Mount is completed"<< std::endl;
599 static inline int clean(const std::string name)
603 ret = ode_secure_clean(name.c_str());
605 std::cerr << "Error : " << ret <<std::endl;
611 static inline int recovery(const std::string &name)
615 if (name == "internal")
616 ret = ode_internal_encryption_recovery();
617 else if (name == "external")
618 ret = ode_external_encryption_recovery();
621 std::cerr << "Error : " << ret << std::endl;
626 int main(int argc, char* argv[])
628 int opt = 0, luks_opt = 0, index, ret = 0;
630 struct option options[] = {
631 {"help", no_argument, 0, 'h'},
632 {"mount", required_argument, 0, 'm'},
633 {"umount", required_argument, 0, 'u'},
634 {"encrypt", required_argument, 0, 'e'},
635 {"decrypt", required_argument, 0, 'd'},
636 {"luks" , required_argument, 0, 'l'},
637 {"luks_sync" , required_argument, 0, 'L'},
638 {"keys" , required_argument, 0, 'k'},
639 {"state", required_argument, 0, 's'},
640 {"waitmnt", required_argument, 0, 'w'},
641 {"clean", required_argument, 0, 'c'},
642 {"recovery", required_argument, 0, 'r'},
646 struct option luks_options[] = {
647 {"device", required_argument, 0, 'D'},
648 {"mapping", required_argument, 0, 'M'},
649 {"synchronous", no_argument, 0, 'S'},
658 std::string mapping, device, op;
661 while ((opt = getopt_long(argc, argv, "m:u:e:d:l:L:p:k:s:w:c:r:h", options, &index)) != -1) {
667 ret = umount(optarg);
670 ret = encrypt_storage(optarg);
673 ret = decrypt_storage(optarg);
677 // No break on purpose. Logic is the same just the flag is different.
680 while ((luks_opt = getopt_long(argc, argv, "D:M:", luks_options, &index)) != -1) {
689 ret = usage(argv[0]);
693 ret = luks(sync, op, device, mapping);
697 while ((luks_opt = getopt_long(argc, argv, "D:", luks_options, &index)) != -1) {
703 ret = usage(argv[0]);
707 ret = keys(op, device);
710 ret = change_password(optarg);
713 ret = wait_for_mount(optarg);
716 ret = get_state(optarg);
722 ret = recovery(optarg);
732 ret = usage(argv[0]);
736 return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;