RET_ON_FAILURE(client.connect() == 0, ODE_ERROR_CONNECTION_REFUSED);
ExternalEncryption external = client.createInterface<ExternalEncryption>();
- return external.changePassword(new_password, old_password);
+ return external.changePassword(old_password, new_password);
}
int ode_external_encryption_get_state(int* state)
RET_ON_FAILURE(client.connect() == 0, ODE_ERROR_CONNECTION_REFUSED);
InternalEncryption internal = client.createInterface<InternalEncryption>();
- return internal.changePassword(new_password, old_password);
+ return internal.changePassword(old_password, new_password);
}
int ode_internal_encryption_get_state(int* state)
launchpad.cpp
ext4-tool.cpp
app-bundle.cpp
+ file-footer.cpp
secure-erase.cpp
block-device.cpp
internal-encryption.cpp
#include <klay/exception.h>
#include <klay/filesystem.h>
+#include "../file-footer.h"
+
#include "dmcrypt-engine.h"
namespace ode {
destroyCryptoBlkDev(DM_LABEL);
}
+const DMCryptEngine::data DMCryptEngine::getKeyMeta()
+{
+ return FileFooter::read(source);
+}
+
+void DMCryptEngine::setKeyMeta(const data &meta)
+{
+ FileFooter::write(source, meta);
+}
+
} // namespace ode
void encrypt(const data &key);
void decrypt(const data &key);
+ const data getKeyMeta();
+ void setKeyMeta(const data &data);
+
private:
std::string source, destination;
CryptInfo cryptInfo;
#include <klay/audit/logger.h>
#include <klay/exception.h>
+#include "../file-footer.h"
+
#include "ecryptfs-engine.h"
namespace ode {
return -1;
}
+const EcryptfsEngine::data EcryptfsEngine::getKeyMeta()
+{
+ return FileFooter::read(mSource);
+}
+
+void EcryptfsEngine::setKeyMeta(const data &meta)
+{
+ FileFooter::write(mSource, meta);
+}
+
} // namespace ode
void encrypt(const data& key);
void decrypt(const data& key);
- int DoCrypt(const data& key, const char *path, int reqEnc, int excludeMedia);
- int DoEncrypt(const data& key);
- int DoDecrypt(const data& key);
+ const data getKeyMeta();
+ void setKeyMeta(const data &data);
+
+ int DoCrypt(const data &key, const char *path, int reqEnc, int excludeMedia);
+ int DoEncrypt(const data &key);
+ int DoDecrypt(const data &key);
long long CopyImpl(int sfd, int dfd, long long fullsz, bool enctype);
ssize_t FullRead (int fd, void * buf, size_t count);
ssize_t FullWrite (int fd, const void * buf, size_t len);
* See the License for the specific language governing permissions and
* limitations under the License
*/
-#include <klay/filesystem.h>
-#include <klay/audit/logger.h>
-#include <klay/error.h>
-#include <klay/exception.h>
-
-#include "ext4-engine.h"
-#include "../key-manager/key-generator.h"
#include <iostream>
#include <string>
#include <string.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
+#include <klay/error.h>
+#include <klay/exception.h>
+
+#include "../file-footer.h"
+#include "../key-manager/key-generator.h"
+
+#include "ext4-engine.h"
+
namespace ode {
#define EXT4_MAX_KEY_SIZE 64
const Ext4Engine::data generateKeyDesc(const ode::Ext4Engine::data& key)
{
- ode::KeyGenerator KeyGen(EXT4_MAX_KEY_SIZE);
- Ext4Engine::data keyRef1 = KeyGen.SHA512(key);
- Ext4Engine::data keyRef2 = KeyGen.SHA512(keyRef1);
+ Ext4Engine::data keyRef1 = ode::KeyGenerator::SHA512(key);
+ Ext4Engine::data keyRef2 = ode::KeyGenerator::SHA512(keyRef1);
Ext4Engine::data ret(keyRef2.begin(), keyRef2.begin()+EXT4_KEY_DESCRIPTOR_SIZE);
return ret;
::remove(secondMountPoint.c_str());
}
+const Ext4Engine::data Ext4Engine::getKeyMeta()
+{
+ return FileFooter::read(source);
+}
+
+void Ext4Engine::setKeyMeta(const data &data)
+{
+ FileFooter::write(source, data);
+}
+
} // namespace ode
class Ext4Engine final {
public:
- Ext4Engine(const std::string& src, const std::string& dest);
+ Ext4Engine(const std::string &src, const std::string &dest);
Ext4Engine(const Ext4Engine&) = delete;
Ext4Engine(Ext4Engine&&) = delete;
~Ext4Engine();
typedef std::vector<unsigned char> data;
- void mount(const data& key);
+ void mount(const data &key);
void umount();
- void addKey(const data& key);
- void encrypt(const data& key);
- void decrypt(const data& key);
+ void addKey(const data &key);
+ void encrypt(const data &key);
+ void decrypt(const data &key);
+
+ const data getKeyMeta();
+ void setKeyMeta(const data &data);
private:
std::string source, destination;
namespace {
-KeyManager keyManager(EXTERNAL_STORAGE_PATH);
EcryptfsEngine engine(EXTERNAL_STORAGE_PATH, EXTERNAL_STORAGE_PATH);
void killDependedApplications()
INFO("Mounted!!!");
// TODO
// Password Popup
- std::string pw = "tizen";
- KeyManager::data pwData(pw.begin(), pw.end());
- engine.mount(keyManager.getDEK(pwData));
+// std::string pw = "tizen";
+// KeyManager::data pwData(pw.begin(), pw.end());
+// engine.mount(keyManager.getDEK(pwData));
}
}
INFO("Already Ecryptfs Mounted");
}
else {
- std::string pw = "tizen";
- KeyManager::data pwData(pw.begin(), pw.end());
- engine.mount(keyManager.getDEK(pwData));
+// std::string pw = "tizen";
+// KeyManager::data pwData(pw.begin(), pw.end());
+// engine.mount(keyManager.getDEK(pwData));
}
}
else {
int ExternalEncryption::mount(const std::string& password)
{
- bool isVerified = false;
KeyManager::data pwData(password.begin(), password.end());
+ KeyManager keyManager(engine.getKeyMeta());
- try {
- isVerified = keyManager.verifyPassword(pwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -1;
+ if (!keyManager.verifyPassword(pwData)) {
+ return -2;
}
- engine.mount(keyManager.getDEK(pwData));
+ engine.mount(keyManager.getMasterKey(pwData));
return 0;
}
int ExternalEncryption::encrypt(const std::string& password)
{
KeyManager::data pwData(password.begin(), password.end());
+ KeyManager keyManager;
- if (keyManager.isInitialized()) {
- bool isVerified = false;
- try {
- isVerified = keyManager.verifyPassword(pwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -2;
- }
- } else {
- keyManager.initPassword(pwData);
- }
+ keyManager.initPassword(pwData);
+ engine.setKeyMeta(keyManager.serialize());
- KeyManager::data DEK = keyManager.getDEK(pwData);
- auto encryptWorker = [DEK, this]() {
+ KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
+ auto encryptWorker = [MasterKey, this]() {
showProgressUI("Encrypting");
INFO("Close all applications using external storage...");
killDependedApplications();
INFO("Encryption started...");
- engine.encrypt(DEK);
+ engine.encrypt(MasterKey);
INFO("Sync disk...");
sync();
INFO("Encryption completed");
int ExternalEncryption::decrypt(const std::string& password)
{
- bool isVerified = false;
KeyManager::data pwData(password.begin(), password.end());
+ KeyManager keyManager(engine.getKeyMeta());
- try {
- isVerified = keyManager.verifyPassword(pwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -1;
+ if (!keyManager.verifyPassword(pwData)) {
+ return -2;
}
- KeyManager::data DEK = keyManager.getDEK(pwData);
- auto decryptWorker = [DEK, this]() {
+ KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
+ auto decryptWorker = [MasterKey, this]() {
showProgressUI("Decrypting");
INFO("Close all applications using external storage...");
} catch (runtime::Exception& e) {}
INFO("Decryption started...");
- engine.decrypt(DEK);
+ engine.decrypt(MasterKey);
INFO("Sync disk...");
sync();
INFO("Decryption completed");
std::thread asyncWork(decryptWorker);
asyncWork.detach();
- keyManager.clearPassword();
-
return 0;
}
const std::string& newPassword)
{
KeyManager::data oldPwData(oldPassword.begin(), oldPassword.end());
- KeyManager::data newPwData(newPassword.begin(), oldPassword.end());
+ KeyManager::data newPwData(newPassword.begin(), newPassword.end());
+ KeyManager keyManager(engine.getKeyMeta());
- bool isVerified = false;
- try {
- isVerified = keyManager.verifyPassword(newPwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -1;
+ if (!keyManager.verifyPassword(oldPwData)) {
+ return -2;
}
keyManager.changePassword(oldPwData, newPwData);
+ engine.setKeyMeta(keyManager.serialize());
+
return 0;
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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 <fcntl.h>
+
+#include <sstream>
+#include <iomanip>
+
+#include <klay/exception.h>
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
+
+#include "file-footer.h"
+#include "key-manager/key-generator.h"
+
+namespace ode {
+
+namespace {
+
+const std::string getFileName(const std::string &key)
+{
+ KeyGenerator::data hash = KeyGenerator::MD5(KeyGenerator::data(key.begin(), key.end()));
+ std::stringstream fileName;
+
+ fileName << "/opt/etc/.ode_";
+ fileName << std::hex << std::setfill('0') << std::setw(2);
+ for (unsigned int byte : hash) {
+ fileName << byte;
+ }
+
+ return fileName.str();
+}
+
+} // namsepace
+
+const FileFooter::data FileFooter::read(const std::string &key)
+{
+ std::string fileName(getFileName(key));
+
+ INFO("Footer file : " + fileName);
+
+ runtime::File file(fileName);
+ data value(file.size());
+
+ file.open(O_RDONLY);
+ file.read(value.data(), value.size());
+
+ return value;
+}
+
+void FileFooter::write(const std::string &key, const data &value)
+{
+ std::string fileName(getFileName(key));
+
+ INFO("Footer file : " + fileName);
+
+ runtime::File file(fileName);
+
+ file.create(0600);
+ file.write(value.data(), value.size());
+}
+
+} // namespace ode
--- /dev/null
+/*
+ * Copyright (c) 2016 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 __FILE_FOOTER_H__
+#define __FILE_FOOTER_H__
+
+#include <vector>
+#include <string>
+
+namespace ode {
+
+class FileFooter final {
+public:
+ FileFooter() = delete;
+
+ typedef std::vector<unsigned char> data;
+
+ static const data read(const std::string &key);
+ static void write(const std::string &key, const data &value);
+};
+
+} // namespace ode
+#endif // __FILE_FOOTER_H__
namespace {
-KeyManager keyManager(INTERNAL_STORAGE_PATH);
DMCryptEngine engine("/dev/mmcblk0p25", INTERNAL_STORAGE_PATH);
void stopDependedSystemdServices()
int InternalEncryption::mount(const std::string& password)
{
- bool isVerified = false;
KeyManager::data pwData(password.begin(), password.end());
+ KeyManager keyManager(engine.getKeyMeta());
- try {
- isVerified = keyManager.verifyPassword(pwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -1;
+ if (!keyManager.verifyPassword(pwData)) {
+ return -2;
}
- engine.mount(keyManager.getDEK(pwData));
+ engine.mount(keyManager.getMasterKey(pwData));
return 0;
}
int InternalEncryption::encrypt(const std::string& password)
{
KeyManager::data pwData(password.begin(), password.end());
+ KeyManager keyManager;
- if (keyManager.isInitialized()) {
- bool isVerified = false;
- try {
- isVerified = keyManager.verifyPassword(pwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -2;
- }
- } else {
- keyManager.initPassword(pwData);
- }
+ keyManager.initPassword(pwData);
+ engine.setKeyMeta(keyManager.serialize());
- KeyManager::data DEK = keyManager.getDEK(pwData);
- auto encryptWorker = [DEK, this]() {
+ KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
+ auto encryptWorker = [MasterKey, this]() {
showProgressUI("Encrypting");
INFO("Close all processes using internal storage...");
}
INFO("Encryption started...");
- engine.encrypt(DEK);
+ engine.encrypt(MasterKey);
INFO("Sync disk...");
sync();
INFO("Encryption completed");
int InternalEncryption::decrypt(const std::string& password)
{
- bool isVerified = false;
KeyManager::data pwData(password.begin(), password.end());
+ KeyManager keyManager(engine.getKeyMeta());
- try {
- isVerified = keyManager.verifyPassword(pwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -1;
+ if (!keyManager.verifyPassword(pwData)) {
+ return -2;
}
- KeyManager::data DEK = keyManager.getDEK(pwData);
- auto decryptWorker = [DEK, this]() {
+ KeyManager::data MasterKey = keyManager.getMasterKey(pwData);
+ auto decryptWorker = [MasterKey, this]() {
showProgressUI("Decrypting");
INFO("Close all processes using internal storage...");
} catch (runtime::Exception& e) {}
INFO("Decryption started...");
- engine.decrypt(DEK);
+ engine.decrypt(MasterKey);
INFO("Sync disk...");
sync();
INFO("Decryption completed");
std::thread asyncWork(decryptWorker);
asyncWork.detach();
- keyManager.clearPassword();
-
return 0;
}
const std::string& newPassword)
{
KeyManager::data oldPwData(oldPassword.begin(), oldPassword.end());
- KeyManager::data newPwData(newPassword.begin(), oldPassword.end());
+ KeyManager::data newPwData(newPassword.begin(), newPassword.end());
+ KeyManager keyManager(engine.getKeyMeta());
- bool isVerified = false;
- try {
- isVerified = keyManager.verifyPassword(newPwData);
- } catch (runtime::Exception& e) {}
-
- if (!isVerified) {
- return -1;
+ if (!keyManager.verifyPassword(oldPwData)) {
+ return -2;
}
keyManager.changePassword(oldPwData, newPwData);
+ engine.setKeyMeta(keyManager.serialize());
+
return 0;
}
#include "key-generator.h"
#define PBKDF_DEFAULT_ITERATION 1000
-#define AES_256_CBC_IV "01234567890123456"
-#define AES_256_KEY_LEN 32
-#define AES_BLOCK_LEN 16
+
+#ifdef OPENSSL_NO_AES
+#error This requires AES
+#endif
+
+#ifdef OPENSSL_NO_SHA256
+#error This requires SHA256
+#endif
+
+#ifdef OPENSSL_NO_SHA512
+#error This requires SHA512
+#endif
+
+#ifdef OPENSSL_NO_MD5
+#error This requires MD5
+#endif
namespace ode {
-KeyGenerator::KeyGenerator(int size) :
- keySize(size)
+void KeyGenerator::init()
{
- ::OpenSSL_add_all_algorithms();
+ EVP_add_cipher(EVP_aes_256_cbc());
+ EVP_add_digest(EVP_md5());
+ EVP_add_digest(EVP_sha256());
+ EVP_add_digest(EVP_sha512());
}
-KeyGenerator::~KeyGenerator()
+void KeyGenerator::cleanup()
{
+ EVP_cleanup();
}
-const KeyGenerator::data KeyGenerator::PBKDF(const KeyGenerator::data& pass, const KeyGenerator::data& salt)
+
+const KeyGenerator::data KeyGenerator::PBKDF(const data& pass, const data& salt, size_t iteration, size_t resultSize)
{
- data ret(keySize, 0);
- std::string strPass(pass.begin(), pass.end());
- std::string strSalt(salt.begin(), salt.end());
+ data ret(resultSize, 0);
- ::PKCS5_PBKDF2_HMAC((char*)strPass.c_str(), strPass.size(),
- (unsigned char*)strSalt.c_str(), strSalt.size(), PBKDF_DEFAULT_ITERATION,
- EVP_sha256(), keySize, reinterpret_cast<unsigned char*>(ret.data()));
+ ::PKCS5_PBKDF2_HMAC((char *)pass.data(), pass.size(),
+ salt.data(), salt.size(), iteration,
+ EVP_sha256(), resultSize, ret.data());
return ret;
}
-const KeyGenerator::data KeyGenerator::AESEncrypt(const KeyGenerator::data& key, const KeyGenerator::data& in)
+const KeyGenerator::data KeyGenerator::AESEncrypt(const data& in, const data& key, const data& iv)
{
- data ret(keySize, 0);
- std::string strKey(key.begin(), key.end());
- std::string strIn(in.begin(), in.end());
+ data ret(in.size(), 0);
EVP_CIPHER_CTX* ctx;
int outLen, len;
- //if ((strKey.size() != AES_256_KEY_LEN) || (strIn.size() % AES_BLOCK_LEN != 0))
-
ctx = ::EVP_CIPHER_CTX_new();
- ::EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)strKey.c_str(), (unsigned char*)AES_256_CBC_IV);
+ ::EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv.data());
::EVP_CIPHER_CTX_set_padding(ctx, 0);
- ::EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char*>(ret.data()), &len, (unsigned char*)strIn.c_str(), strIn.size());
+ ::EVP_EncryptUpdate(ctx, ret.data(), &len, in.data(), in.size());
outLen = len;
::EVP_EncryptFinal_ex(ctx, &ret[len], &len);
return ret;
}
-const KeyGenerator::data KeyGenerator::AESDecrypt(const KeyGenerator::data& key, const KeyGenerator::data& in)
+const KeyGenerator::data KeyGenerator::AESDecrypt(const data& in, const data& key, const data& iv)
{
- data ret(keySize, 0);
- std::string strKey(key.begin(), key.end());
- std::string strIn(in.begin(), in.end());
+ data ret(in.size(), 0);
EVP_CIPHER_CTX* ctx;
int len, len1;
- //if ((strKey.size() != AES_256_KEY_LEN) || (strIn.size() % AES_BLOCK_LEN != 0))
-
ctx = ::EVP_CIPHER_CTX_new();
- ::EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)strKey.c_str(), (unsigned char*)AES_256_CBC_IV);
+ ::EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key.data(), iv.data());
::EVP_CIPHER_CTX_set_padding(ctx, 0);
- ::EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char*>(ret.data()), &len, (unsigned char*)strIn.c_str(), keySize);
+ ::EVP_DecryptUpdate(ctx, ret.data(), &len, in.data(), in.size());
len1 = len;
return ret;
}
-const KeyGenerator::data KeyGenerator::HMAC(const KeyGenerator::data& original, const KeyGenerator::data& key)
+const KeyGenerator::data KeyGenerator::HMAC(const data& key, const data& in)
{
- data ret(keySize, 0);
-
+ data ret(256 / 8);
unsigned int md_len;
- std::string strOrigin(key.begin(), key.end());
- std::string strKey(original.begin(), original.end());
- std::string result;
- ::HMAC(EVP_sha256(), (unsigned char*)strKey.c_str(), strKey.size(),
- (unsigned char*)strOrigin.c_str(), strOrigin.size(),
- reinterpret_cast<unsigned char*>(ret.data()), &md_len);
+ ::HMAC(EVP_sha256(), key.data(), key.size(), in.data(), in.size(),
+ ret.data(), &md_len);
return ret;
}
-const KeyGenerator::data KeyGenerator::RNG()
+const KeyGenerator::data KeyGenerator::RNG(size_t resultSize)
{
- data ret(keySize);
+ data ret(resultSize);
- ::RAND_bytes(reinterpret_cast<unsigned char*>(ret.data()), keySize);
+ ::RAND_bytes(ret.data(), resultSize);
return ret;
}
-const KeyGenerator::data KeyGenerator::MD5(const KeyGenerator::data& in)
+const KeyGenerator::data KeyGenerator::MD5(const data& in)
{
- data ret(MD5_DIGEST_LENGTH);
+ data ret(128 / 8);
- ::MD5((unsigned char*)in.data(), in.size(), (unsigned char*)ret.data());
+ ::MD5(in.data(), in.size(), ret.data());
return ret;
}
-const KeyGenerator::data KeyGenerator::SHA512(const KeyGenerator::data& in)
+const KeyGenerator::data KeyGenerator::SHA256(const data& in)
+{
+ data ret(256 / 8);
+
+ ::SHA256(in.data(), in.size(), ret.data());
+
+ return ret;
+}
+
+const KeyGenerator::data KeyGenerator::SHA512(const data& in)
{
- data ret(SHA512_DIGEST_LENGTH);
+ data ret(512 / 8);
- ::SHA512((unsigned char*)in.data(), in.size(), (unsigned char*)ret.data());
+ ::SHA512(in.data(), in.size(), ret.data());
return ret;
}
class KeyGenerator final {
public:
- KeyGenerator(int size);
+ KeyGenerator() = delete;
KeyGenerator(const KeyGenerator&) = delete;
KeyGenerator(KeyGenerator&&) = delete;
- ~KeyGenerator();
KeyGenerator& operator=(const KeyGenerator&) = delete;
KeyGenerator& operator=(KeyGenerator&&) = delete;
typedef std::vector<unsigned char> data;
- const data PBKDF(const data& pass, const data& salt);
- const data AESEncrypt(const data& key, const data& in);
- const data AESDecrypt(const data& key, const data& in);
- const data HMAC(const data& original, const data& key);
- const data RNG();
- const data MD5(const data& in);
- const data SHA512(const data& in);
-
-private:
- int keySize;
+ static void init();
+ static void cleanup();
+
+ static const data PBKDF(const data& pass, const data& salt, size_t iteration, size_t resultSize);
+ static const data AESEncrypt(const data& in, const data& key, const data& iv);
+ static const data AESDecrypt(const data& in, const data& key, const data& iv);
+ static const data HMAC(const data& in, const data& key);
+ static const data RNG(size_t resultSize);
+ static const data MD5(const data& in);
+ static const data SHA256(const data& in);
+ static const data SHA512(const data& in);
};
} // namespace ode
* See the License for the specific language governing permissions and
* limitations under the License
*/
+#include <klay/exception.h>
+
#include "key-manager.h"
+#include "key-generator.h"
+
+#define MASTER_KEY_LENGTH (256 / 8)
+#define ITERATION_COUNT 1000
namespace ode {
-KeyManager::KeyManager(const std::string& storeName) :
- store(storeName), keyGen(store.getKeySize())
+KeyManager::KeyManager()
+{
+}
+
+KeyManager::KeyManager(const data& data) :
+ store(data)
{
}
{
}
-bool KeyManager::isInitialized()
+const KeyManager::data KeyManager::serialize() const
{
- return store.isInitialized();
+ return store.serialize();
}
-void KeyManager::initPassword(const KeyManager::data& password)
+const KeyManager::data KeyManager::newMasterKey()
{
- data salt, edk, emk;
- data mk, dek;
+ data masterKey = KeyGenerator::RNG(MASTER_KEY_LENGTH);
+ data masterKeyDigestSalt = KeyGenerator::RNG(store.getMasterKeyDigestSaltLength());
- salt = keyGen.RNG();
- mk = keyGen.PBKDF(password, salt);
- dek = keyGen.RNG();
+ store.setMasterKeyLength(masterKey.size());
- edk = keyGen.AESEncrypt(mk, dek);
- emk = keyGen.HMAC(mk, edk);
+ store.setMasterKeyDigestSalt(masterKeyDigestSalt);
+ store.setMasterKeyDigestIteration(ITERATION_COUNT);
+ store.setMasterKeyDigest(KeyGenerator::PBKDF(masterKey,
+ masterKeyDigestSalt,
+ store.getMasterKeyDigestIteration(),
+ store.getMasterKeyDigestLength()));
- store.setSalt(salt);
- store.setEDK(edk);
- store.setEMK(emk);
- store.flush();
+ return masterKey;
}
-void KeyManager::changePassword(const KeyManager::data& old_password,
- const KeyManager::data& new_password)
+const KeyManager::data KeyManager::getMasterKey(const data& password) const
{
- data salt, edk, emk;
- data mk, dek;
+ data derivedPassword = KeyGenerator::PBKDF(password,
+ store.getPasswordSalt(),
+ store.getPasswordIteration(),
+ store.getMasterKeyLength());
+
+ data masterKeyCandidate = KeyGenerator::AESDecrypt(
+ store.getEncryptedMasterKey(),
+ derivedPassword,
+ KeyGenerator::SHA256(derivedPassword));
+
+ data masterKeyCandidateDigest = KeyGenerator::PBKDF(masterKeyCandidate,
+ store.getMasterKeyDigestSalt(),
+ store.getMasterKeyDigestIteration(),
+ store.getMasterKeyDigestLength());
+
+ if (masterKeyCandidateDigest == store.getMasterKeyDigest()) {
+ return masterKeyCandidate;
+ }
- salt = store.getSalt();
- edk = store.getEDK();
+ throw runtime::Exception("Password doesn't match!");
+}
- mk = keyGen.PBKDF(old_password, salt);
- dek = keyGen.AESDecrypt(mk, edk);
+void KeyManager::setPassword(const data& masterKey, const data& password) {
+ data passwordSalt = KeyGenerator::RNG(store.getPasswordSaltLength());
- salt = keyGen.RNG();
- mk = keyGen.PBKDF(new_password, salt);
- edk = keyGen.AESEncrypt(mk, dek);
- emk = keyGen.HMAC(mk, edk);
+ store.setPasswordSalt(passwordSalt);
+ store.setPasswordIteration(ITERATION_COUNT);
- store.setSalt(salt);
- store.setEDK(edk);
- store.setEMK(emk);
- store.flush();
-}
+ data derivedPassword = KeyGenerator::PBKDF(password,
+ store.getPasswordSalt(),
+ store.getPasswordIteration(),
+ store.getMasterKeyLength());
-bool KeyManager::verifyPassword(const KeyManager::data& password)
-{
- data salt, edk, emk;
- data mk;
+ store.setEncryptedMasterKey(KeyGenerator::AESEncrypt(
+ masterKey,
+ derivedPassword,
+ KeyGenerator::SHA256(derivedPassword)));
+}
- salt = store.getSalt();
- edk = store.getEDK();
- emk = store.getEMK();
- mk = keyGen.PBKDF(password, salt);
+void KeyManager::initPassword(const data& password)
+{
+ store.setCipherName("aes");
+ store.setCipherMode("cbc-essiv:sha256");
+ store.setHashSpec("sha256");
- if (emk == keyGen.HMAC(mk, edk)) {
- return true;
- } else {
- return false;
- }
+ data masterKey = newMasterKey();
+ setPassword(newMasterKey(), password);
}
-void KeyManager::clearPassword()
+void KeyManager::changePassword(const data& old_password,
+ const data& new_password)
{
- store.remove();
+ try {
+ setPassword(getMasterKey(old_password), new_password);
+ } catch (runtime::Exception &e) {
+ throw runtime::Exception("Password doesn't match!");
+ }
}
-KeyManager::data KeyManager::getDEK(const KeyManager::data& password)
+bool KeyManager::verifyPassword(const data& password) const
{
- data salt, edk;
- data mk;
-
- salt = store.getSalt();
- edk = store.getEDK();
-
- mk = keyGen.PBKDF(password, salt);
-
- return keyGen.AESDecrypt(mk, edk);
+ try {
+ getMasterKey(password);
+ } catch (runtime::Exception &e) {
+ return false;
+ }
+ return true;
}
} // namespace ode
#define __KEY_MANAGER_H__
#include "key-store.h"
-#include "key-generator.h"
namespace ode {
class KeyManager final {
public:
- KeyManager(const std::string& storeName);
+ typedef std::vector<unsigned char> data;
+
+ KeyManager();
+ KeyManager(const data&);
KeyManager(const KeyManager&) = delete;
KeyManager(KeyManager&&) = delete;
~KeyManager();
KeyManager& operator=(const KeyManager&) = delete;
KeyManager& operator=(KeyManager&&) = delete;
- typedef std::vector<unsigned char> data;
+ const data serialize() const;
- bool isInitialized();
+ const data newMasterKey();
+ const data getMasterKey(const data& password) const;
+ void setPassword(const data& masterKey, const data& password);
void initPassword(const data& password);
void changePassword(const data& old_password, const data& new_password);
- bool verifyPassword(const data& password);
- void clearPassword();
-
- data getDEK(const data& password);
+ bool verifyPassword(const data& password) const;
private:
KeyStore store;
- KeyGenerator keyGen;
};
} // namespace ode
* limitations under the License
*/
#include <fcntl.h>
+#include <arpa/inet.h>
#include <openssl/md5.h>
#include <algorithm>
#include <klay/audit/logger.h>
#include <klay/exception.h>
-#include "key-generator.h"
#include "key-store.h"
-
-#define FOOTER_FILE_PATH "/opt/etc/.ode_footer"
-
-#define KEY_SIZE (256 / 8)
-#define KEY_ENTRY_SIZE (KEY_SIZE * 4)
-
-#define KEY_HNAME_OFFSET (KEY_SIZE * 0)
-#define KEY_EDK_OFFSET (KEY_SIZE * 1)
-#define KEY_EMK_OFFSET (KEY_SIZE * 2)
-#define KEY_SALT_OFFSET (KEY_SIZE * 3)
+#include "key-generator.h"
namespace ode {
-/*
- * Design: store fixed size 4 elements (NAME, EDK, EMK, Salt)
- * <------------------ 32 byte --------------------->
- * 00h |----------- Hashed KeyStore Name ---------------|
- * 40h |--------------------- EDK ----------------------|
- * 100h |--------------------- EMK ----------------------|
- * 140h |--------------------- SALT ---------------------|
- */
+KeyStore::KeyStore()
+{
+}
-KeyStore::KeyStore(const std::string &name) :
- edk(KEY_SIZE), emk(KEY_SIZE), salt(KEY_SIZE)
+KeyStore::KeyStore(const data &raw)
{
- runtime::File file(FOOTER_FILE_PATH);
+ if (raw.size() <= sizeof(luks)) {
+ throw runtime::Exception("the size of raw data is not enough");
+ }
- hname = KeyGenerator(KEY_SIZE).MD5(data(name.begin(), name.end()));
+ ::memcpy(&luks, raw.data(), sizeof(luks));
+ keyMaterial = data(raw.begin() + sizeof(luks), raw.end());
+}
- if (!file.exists()) {
- offset = -1;
- file.create(0600);
- file.close();
- return;
- }
+KeyStore::~KeyStore()
+{
+}
- file.open(O_RDONLY);
+const KeyStore::data KeyStore::serialize() const
+{
+ data result((unsigned char *)&luks,
+ ((unsigned char *)&luks) + sizeof(LUKSHeader));
+ result.insert(result.end(), keyMaterial.begin(), keyMaterial.end());
- //find matched block offset
- int fileSize = file.size();
- for (offset = 0; offset < fileSize; offset += KEY_ENTRY_SIZE) {
- file.lseek(offset, SEEK_SET);
+ return result;
+}
- data current(KEY_SIZE);
- file.read(current.data(), KEY_SIZE);
+const std::string KeyStore::getCipherName() const
+{
+ return std::string(luks.cipherName);
+}
- if (std::equal(hname.begin(), hname.end(), current.begin())) {
- file.read(edk.data(), KEY_SIZE);
- file.read(emk.data(), KEY_SIZE);
- file.read(salt.data(), KEY_SIZE);
- file.close();
- return;
- }
- }
+const std::string KeyStore::getCipherMode() const
+{
+ return std::string(luks.cipherMode);
+}
+
+const std::string KeyStore::getHashSpec() const
+{
+ return std::string(luks.hashSpec);
+}
- offset = -1;
- file.close();
+void KeyStore::setCipherName(const std::string &name)
+{
+ char *buf = (char *)luks.cipherName;
+ ::strncpy(buf, name.c_str(), sizeof(luks.cipherName) - 2);
+ buf[sizeof(luks.cipherName) - 1] = '\0';
}
-KeyStore::~KeyStore()
+void KeyStore::setCipherMode(const std::string &mode)
{
+ char *buf = (char *)luks.cipherMode;
+ ::strncpy(buf, mode.c_str(), sizeof(luks.cipherMode) - 2);
+ buf[sizeof(luks.cipherMode) - 1] = '\0';
}
-size_t KeyStore::getKeySize() const
+void KeyStore::setHashSpec(const std::string &spec)
{
- return KEY_SIZE;
+ char *buf = (char *)luks.hashSpec;
+ ::strncpy(buf, spec.c_str(), sizeof(luks.hashSpec) - 2);
+ buf[sizeof(luks.hashSpec) - 1] = '\0';
}
-bool KeyStore::isInitialized() const
+unsigned int KeyStore::getMasterKeyLength() const
{
- return offset >= 0;
+ return ::ntohl(luks.keyBytes);
}
-KeyStore::data KeyStore::getEDK() const
+void KeyStore::setMasterKeyLength(unsigned int length)
{
- if (offset < 0) {
- throw runtime::Exception("Store is empty");
- }
- return edk;
+ luks.keyBytes = ::htonl(length);
}
-KeyStore::data KeyStore::getEMK() const
+void KeyStore::setEncryptedMasterKey(const data key)
{
- if (offset < 0) {
- throw runtime::Exception("Store is empty");
+ keyMaterial = key;
+ luks.keyslot[0].active = ::htonl(0x00AC71F3);
+ luks.keyslot[0].stripes = ::htonl(keyMaterial.size() / getMasterKeyLength());
+ luks.keyslot[0].keyMaterialOffset = ::htonl(sizeof(LUKSHeader));
+
+ luks.payloadOffset = sizeof(LUKSHeader) + keyMaterial.size();
+ if (luks.payloadOffset % 512 != 0) {
+ luks.payloadOffset += 512 - luks.payloadOffset % 512;
}
- return emk;
+ luks.payloadOffset = ::htonl(luks.payloadOffset);
}
-KeyStore::data KeyStore::getSalt() const
+const KeyStore::data& KeyStore::getEncryptedMasterKey() const
{
- if (offset < 0) {
- throw runtime::Exception("Store is empty");
- }
- return salt;
+ return keyMaterial;
}
-void KeyStore::setEDK(const KeyStore::data &key)
+const KeyStore::data KeyStore::getPasswordSalt() const
{
- edk = key;
+ unsigned char *buf = (unsigned char *)luks.keyslot[0].passwordSalt;
+ return data(buf, buf + sizeof(luks.keyslot[0].passwordSalt));
}
-void KeyStore::setEMK(const KeyStore::data &key)
+unsigned int KeyStore::getPasswordIteration() const
{
- emk = key;
+ return ::ntohl(luks.keyslot[0].passwordIteration);
}
-void KeyStore::setSalt(const KeyStore::data &key)
+unsigned int KeyStore::getPasswordSaltLength() const
{
- salt = key;
+ return sizeof(luks.keyslot[0].passwordSalt);
}
-void KeyStore::flush()
+void KeyStore::setPasswordSalt(const data salt)
{
- runtime::File file(FOOTER_FILE_PATH);
+ ::memcpy(luks.keyslot[0].passwordSalt, salt.data(),
+ sizeof(luks.keyslot[0].passwordSalt));
+}
- file.open(O_RDWR);
+void KeyStore::setPasswordIteration(unsigned int count)
+{
+ luks.keyslot[0].passwordIteration = ::htonl(count);
+}
- if (offset < 0) {
- //find empty block offset
- int fileSize = file.size();
- data empty = KeyGenerator(KEY_SIZE).MD5(data(0));
+const KeyStore::data KeyStore::getMasterKeyDigest() const
+{
+ unsigned char *buf = (unsigned char *)luks.mkDigest;
+ return data(buf, buf + sizeof(luks.mkDigest));
+}
- for (offset = 0; offset < fileSize; offset += KEY_ENTRY_SIZE) {
- file.lseek(offset, SEEK_SET);
+const KeyStore::data KeyStore::getMasterKeyDigestSalt() const
+{
+ unsigned char *buf = (unsigned char *)luks.mkDigestSalt;
+ return data(buf, buf + sizeof(luks.mkDigestSalt));
+}
- data current(KEY_SIZE);
- file.read(current.data(), KEY_SIZE);
+unsigned int KeyStore::getMasterKeyDigestIteration() const
+{
+ return ::ntohl(luks.mkDigestIteration);
+}
- if (std::equal(empty.begin(), empty.end(), current.begin())) {
- break;
- }
- }
- }
+unsigned int KeyStore::getMasterKeyDigestLength() const
+{
+ return sizeof(luks.mkDigest);
+}
- file.lseek(offset, SEEK_SET);
- file.write(hname.data(), KEY_SIZE);
- file.write(edk.data(), KEY_SIZE);
- file.write(emk.data(), KEY_SIZE);
- file.write(salt.data(), KEY_SIZE);
- file.close();
+unsigned int KeyStore::getMasterKeyDigestSaltLength() const
+{
+ return sizeof(luks.mkDigestSalt);
}
-void KeyStore::remove()
+void KeyStore::setMasterKeyDigest(const data digest)
{
- data empty = KeyGenerator(KEY_SIZE).MD5(data(0));
+ ::memcpy(luks.mkDigest, digest.data(), sizeof(luks.mkDigest));
+}
- runtime::File file(FOOTER_FILE_PATH);
- file.open(O_WRONLY);
- file.lseek(offset, SEEK_SET);
- file.write(empty.data(), KEY_SIZE);
- file.close();
+void KeyStore::setMasterKeyDigestSalt(const data salt)
+{
+ ::memcpy(luks.mkDigestSalt, salt.data(), sizeof(luks.mkDigestSalt));
+}
- offset = -1;
+void KeyStore::setMasterKeyDigestIteration(unsigned int count)
+{
+ luks.mkDigestIteration = ::htonl(count);
}
} // namespace ode
#include <klay/filesystem.h>
+#include "luks.h"
+
namespace ode {
class KeyStore final {
public:
- KeyStore(const std::string &name);
+ typedef std::vector<unsigned char> data;
+
+ KeyStore();
+ KeyStore(const data &raw);
KeyStore(const KeyStore &) = delete;
KeyStore(KeyStore &&) = delete;
~KeyStore();
KeyStore &operator=(const KeyStore &) = delete;
KeyStore &operator=(KeyStore &&) = delete;
- size_t getKeySize() const;
+ const data serialize() const;
- bool isInitialized() const;
+ const std::string getCipherName() const;
+ const std::string getCipherMode() const;
+ const std::string getHashSpec() const;
+ void setCipherName(const std::string &name);
+ void setCipherMode(const std::string &mode);
+ void setHashSpec(const std::string &hash);
- typedef std::vector<unsigned char> data;
+ unsigned int getMasterKeyLength() const;
+ void setMasterKeyLength(unsigned int length);
- data getEDK() const;
- data getEMK() const;
- data getSalt() const;
+ const data& getEncryptedMasterKey() const;
+ void setEncryptedMasterKey(const data salt);
- void setEDK(const data &key);
- void setEMK(const data &key);
- void setSalt(const data &key);
+ const data getPasswordSalt() const;
+ unsigned int getPasswordIteration() const;
+ unsigned int getPasswordSaltLength() const;
+ void setPasswordSalt(const data salt);
+ void setPasswordIteration(unsigned int count);
- void flush();
- void remove();
+ const data getMasterKeyDigest() const;
+ const data getMasterKeyDigestSalt() const;
+ unsigned int getMasterKeyDigestLength() const;
+ unsigned int getMasterKeyDigestSaltLength() const;
+ unsigned int getMasterKeyDigestIteration() const;
+ void setMasterKeyDigest(const data digest);
+ void setMasterKeyDigestSalt(const data salt);
+ void setMasterKeyDigestIteration(unsigned int count);
private:
- data hname, edk, emk, salt;
- int offset;
+ LUKSHeader luks;
+ data keyMaterial;
};
} // namespace ode
--- /dev/null
+/*
+ * Copyright (c) 2016 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 __LUKS_H__
+#define __LUKS_H__
+
+#include <cstdint>
+
+struct LUKSHeader final {
+ char magic[6];
+ uint16_t version;
+ char cipherName[32];
+ char cipherMode[32];
+ char hashSpec[32];
+ uint32_t payloadOffset;
+ uint32_t keyBytes;
+ char mkDigest[20];
+ char mkDigestSalt[32];
+ uint32_t mkDigestIteration;
+ char uuid[40];
+
+ struct {
+ uint32_t active;
+ uint32_t passwordIteration;
+ char passwordSalt[32];
+ uint32_t keyMaterialOffset;
+ uint32_t stripes;
+ } keyslot[1];
+
+ char padding[256];
+
+ LUKSHeader() :
+ magic{'L', 'U', 'K', 'S', 0xba, 0xbe}, version(1)
+ {
+ for (auto &key : keyslot) {
+ unsigned char *buf = (unsigned char*)&key.active;
+ buf[0] = 0x0;
+ buf[1] = 0x0;
+ buf[2] = 0xDE;
+ buf[3] = 0xAD;
+ }
+ }
+};
+
+#endif // __LUKS_H__
#include "rmi/secure-erase.h"
#include "rmi/internal-encryption.h"
#include "rmi/external-encryption.h"
+#include "key-manager/key-generator.h"
#include "server.h"
secureErase.reset(new ode::SecureErase(*this));
internalEncryption.reset(new ode::InternalEncryption(*this));
externalEncryption.reset(new ode::ExternalEncryption(*this));
+
+ ode::KeyGenerator::init();
}
Server::~Server()
{
+ ode::KeyGenerator::cleanup();
}
void Server::run()
ext4-engine.cpp
dmcrypt-engine.cpp
ecryptfs-engine.cpp
+ ../server/file-footer.cpp
../server/engine/ext4-engine.cpp
../server/engine/ecryptfs-engine.cpp
../server/key-manager/key-generator.cpp