E2EE: PBKDF API implementation 15/289115/10
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Fri, 24 Feb 2023 08:58:28 +0000 (09:58 +0100)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 21 Mar 2023 15:25:41 +0000 (16:25 +0100)
Tests included

Change-Id: I4cbe3363690ff116a8c26dba3e6bfca8d9e0dad5

src/e2ee-adaptation-layer/CMakeLists.txt
src/e2ee-adaptation-layer/e2ee-adaptation-layer.cpp
src/e2ee-adaptation-layer/tests.cpp

index 1971096..03cff11 100644 (file)
@@ -21,6 +21,7 @@ SET(TARGET_E2EE_ADAPTATION_LAYER "e2ee-adaptation-layer")
 PKG_CHECK_MODULES(E2EE_ADAPTATION_LAYER_DEP
     REQUIRED
     key-manager # >=0.1.48
+    openssl1.1
 )
 
 SET(E2EE_ADAPTATION_LAYER_SOURCES
index d5b39ec..73d068e 100644 (file)
@@ -19,6 +19,8 @@
 #include <cstring>
 #include <memory>
 
+#include <openssl/evp.h>
+
 #include <ckmc/ckmc-manager.h>
 
 namespace {
@@ -26,6 +28,7 @@ namespace {
 const char* const LABEL = "label";
 const char* const CONTEXT = "context";
 const char* const SECRET_ALIAS = "temporary_shared_e2ee_secret";
+constexpr size_t ITERATIONS = 1000;
 
 typedef std::unique_ptr<struct __ckmc_param_list, decltype(&ckmc_param_list_free)> ParamsPtr;
 
@@ -153,14 +156,36 @@ int ckmew_key_agreement(const char *private_key_alias,
     return ckmc_key_derive(kbkdf_params.get(), SECRET_ALIAS, nullptr, new_key_alias, unexportable);
 }
 
-int ckmew_key_derive_pbkdf2(const char * /*password*/,
-                            const unsigned char * /*salt*/,
-                            size_t /*salt_len*/,
-                            size_t /*new_key_len*/,
-                            const char * /*new_key_alias*/)
+int ckmew_key_derive_pbkdf2(const char *password,
+                            const unsigned char *salt,
+                            size_t salt_len,
+                            size_t new_key_len,
+                            const char *new_key_alias)
 {
-    // TODO
-    return CKMC_ERROR_NONE;
+    if (password == nullptr || salt == nullptr || new_key_alias == nullptr || new_key_len == 0)
+        return CKMC_ERROR_INVALID_PARAMETER;
+
+    unsigned char derived[new_key_len];
+
+    if (1 != PKCS5_PBKDF2_HMAC_SHA1(password,
+                                    strlen(password),
+                                    salt,
+                                    salt_len,
+                                    ITERATIONS,
+                                    new_key_len,
+                                    derived))
+        return CKMC_ERROR_SERVER_ERROR;
+
+    ckmc_key_s* key = nullptr;
+    int ret = ckmc_key_new(derived, new_key_len, CKMC_KEY_AES, nullptr, &key);
+    if (ret != CKMC_ERROR_NONE)
+        return ret;
+
+    ckmc_policy_s unexportable { nullptr, false };
+    ret = ckmc_save_key(new_key_alias, *key, unexportable);
+    ckmc_key_free(key);
+
+    return ret;
 }
 
 int ckmew_get_ocf_cert_chain(char ** /*cert_chain*/, size_t * /*cert_chain_len*/)
index ff743fd..e60d543 100644 (file)
@@ -37,6 +37,11 @@ const KeyAliasPair PEERS2 = { "peer2_ec_private", "peer2_ec_public" };
 const KeyAliasPair WRONG = { "wrong_ec_private", "wrong_ec_public" };
 const KeyAliasPair RSA = { "rsa_private", "rsa_public" };
 
+const char* const DERIVED = "derived";
+
+constexpr size_t SALT_LEN = 16;
+const unsigned char SALT[SALT_LEN] = {};
+
 const ckmc_policy_s UNEXPORTABLE { nullptr, false };
 const ckmc_policy_s EXPORTABLE { nullptr, true };
 
@@ -147,8 +152,6 @@ RUNNER_TEST(TEAL_0010_key_agreement_positive)
 
 RUNNER_TEST(TEAL_0020_key_agreement_wrong_arguments)
 {
-    const char* const DERIVED = "derived";
-
     auto pub_key = getKey(PEERS.pub);
 
     auto invalid = [](const char* prv,
@@ -206,6 +209,99 @@ RUNNER_TEST(TEAL_0030_key_agreement_wrong_aliases)
                   DERIVED);
 }
 
+RUNNER_TEST(TEAL_1000_pbkdf_positive)
+{
+    constexpr size_t KEY_LEN = 32;
+
+    auto plain = create_raw_buffer(createRandomBufferCAPI(512));
+    auto iv = create_raw_buffer(createRandomBufferCAPI(16));
+    auto salt = create_raw_buffer(createRandomBufferCAPI(SALT_LEN));
+
+    auto params = createParamListPtr();
+    setParam(params, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_AES_CTR);
+    setParam(params, CKMC_PARAM_ED_IV, iv.get());
+
+    assert_positive(ckmew_key_derive_pbkdf2, "password", salt->data, salt->size, KEY_LEN, DERIVED);
+    auto remover1 = AliasRemover(DERIVED);
+
+    ckmc_raw_buffer_s* encrypted = nullptr;
+    assert_positive(ckmc_encrypt_data, params.get(), DERIVED, "", *plain.get(), &encrypted);
+    auto encryptedPtr = create_raw_buffer(encrypted);
+
+    auto deriveAndDecrypt = [&encryptedPtr, &params](const char* password,
+                                                     const unsigned char* salt,
+                                                     size_t salt_len,
+                                                     size_t key_len)
+    {
+        const char* const DERIVED2 = "derived2";
+        assert_positive(ckmew_key_derive_pbkdf2, password, salt, salt_len, key_len, DERIVED2);
+        auto remover = AliasRemover(DERIVED2);
+
+        ckmc_raw_buffer_s* decrypted = nullptr;
+        assert_positive(ckmc_decrypt_data,
+                        params.get(),
+                        DERIVED2,
+                        "",
+                        *encryptedPtr.get(),
+                        &decrypted);
+
+        return create_raw_buffer(decrypted);
+    };
+
+    RawBufferPtr decrypted;
+    decrypted = deriveAndDecrypt("password", salt->data, salt->size, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get());
+
+    decrypted = deriveAndDecrypt("wrong", salt->data, salt->size, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+
+    decrypted = deriveAndDecrypt("password", salt->data, salt->size, KEY_LEN - 8);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+
+    decrypted = deriveAndDecrypt("password", salt->data, salt->size - 1, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+
+    decrypted = deriveAndDecrypt("password", plain->data, salt->size, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+}
+
+RUNNER_TEST(TEAL_1010_pbkdf_invalid_arguments)
+{
+    assert_invalid_param(ckmew_key_derive_pbkdf2, nullptr,    SALT,    SALT_LEN, 32, DERIVED);
+    assert_invalid_param(ckmew_key_derive_pbkdf2, "password", nullptr, SALT_LEN, 32, DERIVED);
+    assert_invalid_param(ckmew_key_derive_pbkdf2, "password", SALT,    SALT_LEN, 32, nullptr);
+    assert_invalid_param(ckmew_key_derive_pbkdf2, "password", SALT,    SALT_LEN, 0,  DERIVED);
+
+    auto invalidFormat = [&](size_t key_len) {
+        assert_result(CKMC_ERROR_INVALID_FORMAT,
+                      ckmew_key_derive_pbkdf2,
+                      "password",
+                      SALT,
+                      SALT_LEN,
+                      key_len,
+                      DERIVED);
+    };
+    invalidFormat(64);
+    invalidFormat(31);
+    invalidFormat(8);
+    invalidFormat(1);
+}
+
+RUNNER_TEST(TEAL_1020_pbkdf_wrong_alias)
+{
+    assert_positive(ckmew_key_derive_pbkdf2, "password", SALT, SALT_LEN, 32, DERIVED);
+
+    auto remover = AliasRemover(DERIVED);
+
+    assert_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+                  ckmew_key_derive_pbkdf2,
+                  "password",
+                  SALT,
+                  SALT_LEN,
+                  32,
+                  DERIVED);
+}
+
 int main(int argc, char *argv[])
 {
     return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);