cryptfshw: Introduce QSEECom backend implementation

Some code snippets are taken from the following set of changes:

    cryptfshw: Setup boilerplate items before actual implementation

    * This is also in preparation for splitting this into two impls:
      one for ioctl() calls and one for dlsym() calls
   * This includes:
    - Add a .clang-format file and format the source
    - Add an init rc file
    - Add service.cpp
    - Convert struct to a class
    - Setup Android.bp for building the HIDL hal and run through bpfix
    - Setup items shared between both impls in Android.bp

    Change-Id: I1db3773f49883aa492a041e794303a11dfa2da51
    Signed-off-by: Michael Bestas <mkbestas@lineageos.org>

    cryptfshw: dlsym: Wire up the implementation

    Change-Id: I10473223ffd8f63dec759700a0fd989241af18a3

Change-Id: I7f27355a8a435f013b3b09cd5efac45452f7a4f3
diff --git a/.clang-format b/.clang-format
new file mode 120000
index 0000000..973b2fa
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1 @@
+../../../build/soong/scripts/system-clang-format
\ No newline at end of file
diff --git a/cryptfshw/1.0/Android.bp b/cryptfshw/1.0/Android.bp
index 8670d24..fe511ff 100644
--- a/cryptfshw/1.0/Android.bp
+++ b/cryptfshw/1.0/Android.bp
@@ -12,28 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_shared {
-    // FIXME: this should only be -impl for a passthrough hal.
-    // In most cases, to convert this to a binderized implementation, you should:
-    // - change '-impl' to '-service' here and make it a cc_binary instead of a
-    //   cc_library_shared.
-    // - add a *.rc file for this module.
-    // - delete HIDL_FETCH_I* functions.
-    // - call configureRpcThreadpool and registerAsService on the instance.
-    // You may also want to append '-impl/-service' with a specific identifier like
-    // '-vendor' or '-<hardware identifier>' etc to distinguish it.
-    name: "vendor.qti.hardware.cryptfshw@1.0-impl",
-    relative_install_path: "hw",
-    // FIXME: this should be 'vendor: true' for modules that will eventually be
-    // on AOSP.
-    proprietary: true,
+cc_library_static {
+    name: "vendor.qti.hardware.cryptfshw@1.0-base",
+    vendor: true,
+    defaults: ["hidl_defaults"],
     srcs: [
         "CryptfsHw.cpp",
+        "CryptfsHwUtils.cpp",
     ],
+    export_include_dirs: ["."],
+    header_libs: ["generated_kernel_headers"],
     shared_libs: [
+        "libbase",
         "libhidlbase",
-        "libhidltransport",
         "libutils",
         "vendor.qti.hardware.cryptfshw@1.0",
-    ],
+    ]
 }
diff --git a/cryptfshw/1.0/CryptfsHw.cpp b/cryptfshw/1.0/CryptfsHw.cpp
index ab43760..ded06b2 100644
--- a/cryptfshw/1.0/CryptfsHw.cpp
+++ b/cryptfshw/1.0/CryptfsHw.cpp
@@ -14,8 +14,18 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "vendor.qti.hardware.cryptfshw@1.0-impl-qti"
+
 #include "CryptfsHw.h"
 
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <dlfcn.h>
+#include <linux/qseecom.h>
+
+#include "Types.h"
+
 namespace vendor {
 namespace qti {
 namespace hardware {
@@ -23,34 +33,85 @@
 namespace V1_0 {
 namespace implementation {
 
+using ::android::base::GetProperty;
+using ::android::base::unique_fd;
+
+namespace {
+bool IsHwDiskEncryption(const hidl_string& encryption_mode) {
+    if (encryption_mode == "aes-xts") {
+        LOG_TO(SYSTEM, DEBUG) << "HW based disk encryption is enabled";
+        return true;
+    }
+    return false;
+}
+};  // anonymous namespace
+
+CryptfsHw::CryptfsHw(std::unique_ptr<ICryptfsHwController> controller)
+    : controller_(std::move(controller)) {
+    std::string bootdevice = GetProperty("ro.boot.bootdevice", "");
+
+    if (bootdevice.find("ufs") != std::string::npos) {
+        /*
+         * All UFS based devices has ICE in it. So we dont need
+         * to check if corresponding device exists or not
+         */
+        usage_ = CRYPTFS_HW_KM_USAGE_UFS_ICE_DISK_ENCRYPTION;
+    } else if (bootdevice.find("sdhc") != std::string::npos && access("/dev/icesdcc", F_OK) != -1) {
+        usage_ = CRYPTFS_HW_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION;
+    } else {
+        usage_ = CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION;
+    }
+}
+
 // Methods from ::vendor::qti::hardware::cryptfshw::V1_0::ICryptfsHw follow.
 Return<int32_t> CryptfsHw::setIceParam(uint32_t flag) {
-    // TODO implement
-    return int32_t {};
+#ifdef QSEECOM_IOCTL_SET_ICE_INFO
+    int32_t ret = -1;
+    qseecom_ice_data_t ice_data;
+    unique_fd qseecom_fd(open("/dev/qseecom", O_RDWR));
+    if (qseecom_fd < 0) return ret;
+    ice_data.flag = static_cast<int>(flag);
+    ret = ioctl(qseecom_fd, QSEECOM_IOCTL_SET_ICE_INFO, &ice_data);
+    return ret;
+#else
+    (void)flag;
+    return -1;
+#endif
 }
 
 Return<int32_t> CryptfsHw::setKey(const hidl_string& passwd, const hidl_string& enc_mode) {
-    // TODO implement
-    return int32_t {};
+    int err = -1;
+
+    if (!IsHwDiskEncryption(enc_mode)) return err;
+
+    err = controller_->createKey(usage_, passwd.c_str());
+    if (err < 0) {
+        if (ERR_MAX_PASSWORD_ATTEMPTS == err)
+            LOG_TO(SYSTEM, INFO) << "Maximum wrong password attempts reached, will erase userdata";
+    }
+
+    return err;
 }
 
-Return<int32_t> CryptfsHw::updateKey(const hidl_string& oldpw, const hidl_string& newpw, const hidl_string& enc_mode) {
-    // TODO implement
-    return int32_t {};
+Return<int32_t> CryptfsHw::updateKey(const hidl_string& oldpw, const hidl_string& newpw,
+                                     const hidl_string& enc_mode) {
+    int err = -1;
+
+    if (!IsHwDiskEncryption(enc_mode)) return err;
+
+    err = controller_->updateKey(usage_, oldpw.c_str(), newpw.c_str());
+    if (err < 0) {
+        if (ERR_MAX_PASSWORD_ATTEMPTS == err)
+            LOG_TO(SYSTEM, INFO) << "Maximum wrong password attempts reached, will erase userdata";
+    }
+
+    return err;
 }
 
 Return<int32_t> CryptfsHw::clearKey() {
-    // TODO implement
-    return int32_t {};
+    return controller_->wipeKey(usage_);
 }
 
-
-// Methods from ::android::hidl::base::V1_0::IBase follow.
-
-//ICryptfsHw* HIDL_FETCH_ICryptfsHw(const char* /* name */) {
-    //return new CryptfsHw();
-//}
-//
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace cryptfshw
diff --git a/cryptfshw/1.0/CryptfsHw.h b/cryptfshw/1.0/CryptfsHw.h
index c73984e..5295a4d 100644
--- a/cryptfshw/1.0/CryptfsHw.h
+++ b/cryptfshw/1.0/CryptfsHw.h
@@ -16,9 +16,12 @@
 
 #pragma once
 
+#include <android-base/macros.h>
 #include <vendor/qti/hardware/cryptfshw/1.0/ICryptfsHw.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
+
+#include <memory>
+
+#include "ICryptfsHwController.h"
 
 namespace vendor {
 namespace qti {
@@ -27,28 +30,27 @@
 namespace V1_0 {
 namespace implementation {
 
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
 using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
 
-struct CryptfsHw : public ICryptfsHw {
+class CryptfsHw : public ICryptfsHw {
+  public:
+    CryptfsHw(std::unique_ptr<ICryptfsHwController> controller);
+
     // Methods from ::vendor::qti::hardware::cryptfshw::V1_0::ICryptfsHw follow.
     Return<int32_t> setIceParam(uint32_t flag) override;
     Return<int32_t> setKey(const hidl_string& passwd, const hidl_string& enc_mode) override;
-    Return<int32_t> updateKey(const hidl_string& oldpw, const hidl_string& newpw, const hidl_string& enc_mode) override;
+    Return<int32_t> updateKey(const hidl_string& oldpw, const hidl_string& newpw,
+                              const hidl_string& enc_mode) override;
     Return<int32_t> clearKey() override;
 
-    // Methods from ::android::hidl::base::V1_0::IBase follow.
+  private:
+    std::unique_ptr<ICryptfsHwController> controller_;
+    int usage_;
 
+    DISALLOW_IMPLICIT_CONSTRUCTORS(CryptfsHw);
 };
 
-// FIXME: most likely delete, this is only for passthrough implementations
-// extern "C" ICryptfsHw* HIDL_FETCH_ICryptfsHw(const char* name);
-
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace cryptfshw
diff --git a/cryptfshw/1.0/CryptfsHwUtils.cpp b/cryptfshw/1.0/CryptfsHwUtils.cpp
new file mode 100644
index 0000000..8efbe68
--- /dev/null
+++ b/cryptfshw/1.0/CryptfsHwUtils.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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 "CryptfsHwUtils.h"
+
+#include <algorithm>
+#include <cstring>
+
+namespace vendor {
+namespace qti {
+namespace hardware {
+namespace cryptfshw {
+namespace V1_0 {
+namespace implementation {
+
+void* secure_memset(void* v, int c, size_t n) {
+    auto p = reinterpret_cast<volatile unsigned char*>(v);
+    while (n--) *p++ = c;
+    return v;
+}
+
+void GetTmpPasswd(const char* passwd, unsigned char* tmp_passwd, size_t buf_len) {
+    secure_memset(tmp_passwd, 0, buf_len);
+    if (passwd) {
+        size_t passwd_len = strnlen(passwd, buf_len);
+        memcpy(tmp_passwd, passwd, passwd_len);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cryptfshw
+}  // namespace hardware
+}  // namespace qti
+}  // namespace vendor
diff --git a/cryptfshw/1.0/CryptfsHwUtils.h b/cryptfshw/1.0/CryptfsHwUtils.h
new file mode 100644
index 0000000..47d97c0
--- /dev/null
+++ b/cryptfshw/1.0/CryptfsHwUtils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <cstddef>
+
+namespace vendor {
+namespace qti {
+namespace hardware {
+namespace cryptfshw {
+namespace V1_0 {
+namespace implementation {
+
+void* secure_memset(void* v, int c, size_t n);
+void GetTmpPasswd(const char* passwd, unsigned char* tmp_passwd, size_t buf_len);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cryptfshw
+}  // namespace hardware
+}  // namespace qti
+}  // namespace vendor
diff --git a/cryptfshw/1.0/ICryptfsHwController.h b/cryptfshw/1.0/ICryptfsHwController.h
new file mode 100644
index 0000000..0748140
--- /dev/null
+++ b/cryptfshw/1.0/ICryptfsHwController.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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.
+ */
+
+#pragma once
+
+namespace vendor {
+namespace qti {
+namespace hardware {
+namespace cryptfshw {
+namespace V1_0 {
+namespace implementation {
+
+// interface wrapper
+class ICryptfsHwController {
+  public:
+    virtual ~ICryptfsHwController() = default;
+
+    virtual int createKey(int usage, const char* passwd) = 0;
+    virtual int updateKey(int usage, const char* oldpw, const char* newpw) = 0;
+    virtual int wipeKey(int usage) = 0;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cryptfshw
+}  // namespace hardware
+}  // namespace qti
+}  // namespace vendor
diff --git a/cryptfshw/1.0/Types.h b/cryptfshw/1.0/Types.h
new file mode 100644
index 0000000..604afd4
--- /dev/null
+++ b/cryptfshw/1.0/Types.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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.
+ */
+
+#pragma once
+
+/*
+ * When device comes up or when user tries to change the password, user can
+ * try wrong password upto a certain number of times. If user enters wrong
+ * password further, HW would wipe all disk encryption related crypto data
+ * and would return an error ERR_MAX_PASSWORD_ATTEMPTS to VOLD. VOLD would
+ * wipe userdata partition once this error is received.
+ */
+constexpr auto ERR_MAX_PASSWORD_ATTEMPTS = -10;
+constexpr auto MAX_PASSWORD_LEN = 32;
+constexpr auto QTI_ICE_STORAGE_UFS = 1;
+constexpr auto QTI_ICE_STORAGE_SDCC = 2;
+
+constexpr auto CRYPTFS_HW_UP_CHECK_COUNT = 10;
+constexpr auto CRYPTFS_HW_CREATE_KEY_FAILED = -7;
+constexpr auto CRYPTFS_HW_WIPE_KEY_FAILED = -8;
+constexpr auto CRYPTFS_HW_UPDATE_KEY_FAILED = -9;
+constexpr auto CRYPTFS_HW_KMS_MAX_FAILURE = -10;
+
+enum cryptfs_hw_key_management_usage_type {
+    CRYPTFS_HW_KM_USAGE_DISK_ENCRYPTION = 0x01,
+    CRYPTFS_HW_KM_USAGE_FILE_ENCRYPTION = 0x02,
+    CRYPTFS_HW_KM_USAGE_UFS_ICE_DISK_ENCRYPTION = 0x03,
+    CRYPTFS_HW_KM_USAGE_SDCC_ICE_DISK_ENCRYPTION = 0x04,
+    CRYPTFS_HW_KM_USAGE_MAX
+};
diff --git a/cryptfshw/1.0/qsee/Android.bp b/cryptfshw/1.0/qsee/Android.bp
new file mode 100644
index 0000000..b06e286
--- /dev/null
+++ b/cryptfshw/1.0/qsee/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2019 The LineageOS Project
+//
+// 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.
+
+cc_binary {
+    name: "vendor.qti.hardware.cryptfshw@1.0-service-qti.qsee",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["vendor.qti.hardware.cryptfshw@1.0-service-qti.qsee.rc"],
+    owner: "qti",
+    srcs: [
+        "QSEEComController.cpp",
+        "service.cpp",
+    ],
+    arch: {
+        arm: {
+            shared_libs: [
+                "libhwbinder",
+            ],
+            cflags: ["-DARCH_ARM_32"],
+        },
+    },
+    product_variables: {
+        lineage: {
+            should_wait_for_qsee: {
+                cflags: ["-DWAIT_FOR_QSEE"],
+            },
+        },
+    },
+    header_libs: ["generated_kernel_headers"],
+    shared_libs: [
+        "libbase",
+        "libdl",
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+        "vendor.qti.hardware.cryptfshw@1.0",
+    ],
+    static_libs: ["vendor.qti.hardware.cryptfshw@1.0-base"],
+}
diff --git a/cryptfshw/1.0/qsee/QSEEComController.cpp b/cryptfshw/1.0/qsee/QSEEComController.cpp
new file mode 100644
index 0000000..9cc5b2b
--- /dev/null
+++ b/cryptfshw/1.0/qsee/QSEEComController.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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.
+ */
+
+#define LOG_TAG "vendor.qti.hardware.cryptfshw@1.0-impl-qti.qsee"
+
+#include "QSEEComController.h"
+
+#include <CryptfsHwUtils.h>
+#include <Types.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <dlfcn.h>
+
+#include <thread>
+
+namespace {
+constexpr char kFilename[] = "libQSEEComAPI.so";
+
+#ifdef WAIT_FOR_QSEE
+bool IsQseecomUp() {
+    using namespace std::chrono_literals;
+    for (size_t i = 0; i < CRYPTFS_HW_UP_CHECK_COUNT; i++) {
+        if (::android::base::GetBoolProperty("sys.keymaster.loaded", false)) {
+            return true;
+        }
+        std::this_thread::sleep_for(100ms);
+    }
+
+    LOG(ERROR) << "Timed out waiting for QSEECom";
+    return false;
+}
+#endif
+}  // anonymous namespace
+
+namespace vendor {
+namespace qti {
+namespace hardware {
+namespace cryptfshw {
+namespace V1_0 {
+namespace implementation {
+namespace qsee {
+
+Controller::Controller() {
+    std::shared_ptr<void> handle(dlopen(kFilename, RTLD_LAZY | RTLD_LOCAL), [this](void* p) {
+        mFn_create_key = nullptr;
+        mFn_update_key_user_info = nullptr;
+        mFn_wipe_key = nullptr;
+
+        if (p != nullptr) {
+            int err = dlclose(p);
+            p = nullptr;
+            if (err != 0) {
+                LOG(ERROR) << "FAILED TO CLOSE LIBRARY " << kFilename;
+            }
+        }
+    });
+    if (handle == nullptr) {
+        LOG(ERROR) << "FAILED TO LOAD LIBRARY " << kFilename << ": " << dlerror();
+        return;
+    }
+
+#ifdef WAIT_FOR_QSEE
+    if (!IsQseecomUp()) {
+        LOG_TO(SYSTEM, ERROR)
+                << "Timed out waiting for QSEECom listeners. Aborting FDE key operation";
+        return;
+    }
+#endif
+
+    handle_ = handle;
+    mFn_create_key = loadFunction<int (*)(int, void*)>("QSEECom_create_key");
+    mFn_update_key_user_info =
+            loadFunction<int (*)(int, void*, void*)>("QSEECom_update_key_user_info");
+    mFn_wipe_key = loadFunction<int (*)(int)>("QSEECom_wipe_key");
+}
+
+template <typename Function>
+Function Controller::loadFunction(const char* name) {
+    void* fn = dlsym(handle_.get(), name);
+    if (fn == nullptr) {
+        LOG(ERROR) << "loadFunction -- failed to load function " << name;
+    }
+    return reinterpret_cast<Function>(fn);
+}
+
+int Controller::createKey(int usage, const char* passwd) {
+    int32_t ret;
+    unsigned char hash32[MAX_PASSWORD_LEN];
+
+    if (mFn_create_key == nullptr) return CRYPTFS_HW_UPDATE_KEY_FAILED;
+
+    GetTmpPasswd(passwd, hash32, MAX_PASSWORD_LEN);
+
+    ret = mFn_create_key(usage, hash32);
+    if (ret) {
+        LOG_TO(SYSTEM, ERROR) << "Error::Qseecom call to create encryption key for usage " << usage
+                              << " failed with ret = " << ret << ", errno = " << errno;
+        if (errno == ERANGE) {
+            ret = CRYPTFS_HW_KMS_MAX_FAILURE;
+        } else {
+            ret = CRYPTFS_HW_CREATE_KEY_FAILED;
+        }
+    } else {
+        LOG_TO(SYSTEM, ERROR) << "SUCESS::Qseecom call to create encryption key for usage " << usage
+                              << " success with ret = " << ret;
+    }
+
+    secure_memset(hash32, 0, MAX_PASSWORD_LEN);
+
+    return ret;
+}
+
+int Controller::updateKey(int usage, const char* oldpw, const char* newpw) {
+    int32_t ret;
+    unsigned char current_hash32[MAX_PASSWORD_LEN], new_hash32[MAX_PASSWORD_LEN];
+
+    if (mFn_update_key_user_info == nullptr) return CRYPTFS_HW_UPDATE_KEY_FAILED;
+
+    GetTmpPasswd(oldpw, current_hash32, MAX_PASSWORD_LEN);
+    GetTmpPasswd(newpw, new_hash32, MAX_PASSWORD_LEN);
+
+    ret = mFn_update_key_user_info(usage, current_hash32, new_hash32);
+    if (ret) {
+        LOG_TO(SYSTEM, ERROR) << "Error::Qseecom call to update the encryption key for usage "
+                              << usage << " failed with ret = " << ret << ", errno = " << errno;
+        if (errno == ERANGE) {
+            ret = CRYPTFS_HW_KMS_MAX_FAILURE;
+        } else {
+            ret = CRYPTFS_HW_UPDATE_KEY_FAILED;
+        }
+    } else {
+        LOG_TO(SYSTEM, ERROR) << "SUCCESS::Qseecom call to update the encryption key for usage "
+                              << usage << " success with ret = " << ret;
+    }
+
+    secure_memset(current_hash32, 0, MAX_PASSWORD_LEN);
+    secure_memset(new_hash32, 0, MAX_PASSWORD_LEN);
+
+    return ret;
+}
+
+int Controller::wipeKey(int usage) {
+    int32_t ret;
+
+    if (mFn_wipe_key == nullptr) return CRYPTFS_HW_UPDATE_KEY_FAILED;
+
+    ret = mFn_wipe_key(usage);
+    if (ret) {
+        LOG_TO(SYSTEM, ERROR) << "Error::Qseecom call to wipe the encryption key for usage "
+                              << usage << " failed with ret = " << ret << ", errno = " << errno;
+        ret = CRYPTFS_HW_WIPE_KEY_FAILED;
+    } else {
+        LOG_TO(SYSTEM, ERROR) << "SUCCESS::Qseecom call to wipe the encryption key for usage "
+                              << usage << " success with ret = " << ret;
+    }
+    return ret;
+}
+
+}  // namespace qsee
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cryptfshw
+}  // namespace hardware
+}  // namespace qti
+}  // namespace vendor
diff --git a/cryptfshw/1.0/qsee/QSEEComController.h b/cryptfshw/1.0/qsee/QSEEComController.h
new file mode 100644
index 0000000..6593b2c
--- /dev/null
+++ b/cryptfshw/1.0/qsee/QSEEComController.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <ICryptfsHwController.h>
+#include <android-base/macros.h>
+
+#include <memory>
+
+namespace vendor {
+namespace qti {
+namespace hardware {
+namespace cryptfshw {
+namespace V1_0 {
+namespace implementation {
+namespace qsee {
+
+// interface wrapper
+class Controller : public ICryptfsHwController {
+  public:
+    Controller();
+    int createKey(int usage, const char* passwd) override;
+    int updateKey(int usage, const char* oldpw, const char* newpw) override;
+    int wipeKey(int usage) override;
+
+  private:
+    template <typename Function>
+    Function loadFunction(const char* name);
+    std::shared_ptr<void> handle_;
+
+    int (*mFn_create_key)(int, void*);
+    int (*mFn_update_key_user_info)(int, void*, void*);
+    int (*mFn_wipe_key)(int);
+
+    DISALLOW_COPY_AND_ASSIGN(Controller);
+    Controller(Controller&&) = delete;
+    Controller& operator=(Controller&&) = delete;
+};
+
+}  // namespace qsee
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cryptfshw
+}  // namespace hardware
+}  // namespace qti
+}  // namespace vendor
diff --git a/cryptfshw/1.0/qsee/service.cpp b/cryptfshw/1.0/qsee/service.cpp
new file mode 100644
index 0000000..5c9100e
--- /dev/null
+++ b/cryptfshw/1.0/qsee/service.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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.
+ */
+
+#define LOG_TAG "vendor.qti.hardware.cryptfshw@1.0-service-qti.qsee"
+// #define LOG_NDEBUG 0
+
+#include "QSEEComController.h"
+
+#define CRYPTFS_HW_BACKEND qsee
+#include <service.impl.h>
diff --git a/cryptfshw/1.0/qsee/vendor.qti.hardware.cryptfshw@1.0-service-qti.qsee.rc b/cryptfshw/1.0/qsee/vendor.qti.hardware.cryptfshw@1.0-service-qti.qsee.rc
new file mode 100644
index 0000000..8e17d46
--- /dev/null
+++ b/cryptfshw/1.0/qsee/vendor.qti.hardware.cryptfshw@1.0-service-qti.qsee.rc
@@ -0,0 +1,5 @@
+service cryptfshw-1-0 /vendor/bin/hw/vendor.qti.hardware.cryptfshw@1.0-service-qti.qsee
+    class early_hal
+    user system
+    group system
+    writepid /dev/cpuset/system-background/tasks
diff --git a/cryptfshw/1.0/service.impl.h b/cryptfshw/1.0/service.impl.h
new file mode 100644
index 0000000..3a10d07
--- /dev/null
+++ b/cryptfshw/1.0/service.impl.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The LineageOS Project
+ *
+ * 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 CRYPTFS_HW_BACKEND
+#error "CRYPTFS_HW_BACKEND must be set before including this file."
+#endif
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#ifdef ARCH_ARM_32
+#include <hwbinder/ProcessState.h>
+#endif
+
+#include <CryptfsHw.h>
+
+using ::android::OK;
+using ::android::status_t;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+
+using ::vendor::qti::hardware::cryptfshw::V1_0::implementation::CryptfsHw;
+using ::vendor::qti::hardware::cryptfshw::V1_0::implementation::ICryptfsHwController;
+using ::vendor::qti::hardware::cryptfshw::V1_0::implementation::CRYPTFS_HW_BACKEND::Controller;
+
+int main() {
+#ifdef ARCH_ARM_32
+    android::hardware::ProcessState::initWithMmapSize((size_t)16384);
+#endif
+
+    LOG(DEBUG) << "CryptfsHw HAL service is starting.";
+
+    auto controller = std::make_unique<Controller>();
+    android::sp<CryptfsHw> cryptfsHw = new CryptfsHw(std::move(controller));
+
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    status_t status = cryptfsHw->registerAsService();
+    if (status == OK) {
+        LOG(DEBUG) << "CryptfsHw HAL service is ready.";
+        joinRpcThreadpool();
+    } else {
+        LOG(ERROR) << "Could not register service for CryptfsHw HAL CryptfsHw Iface (" << status
+                   << ")";
+    }
+
+    // In normal operation, we don't expect the thread pool to shutdown
+    LOG(ERROR) << "CryptfsHw HAL service is shutting down.";
+    return 1;
+}