[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [ksecrets] src/runtime/ksecrets_store: Starting to implement createCollection
From: Valentin Rusu <kde () rusu ! info>
Date: 2015-08-15 22:02:45
Message-ID: E1ZQjXJ-0005RD-N5 () scm ! kde ! org
[Download RAW message or body]
Git commit 58c491477506a1fe6adbd04412da565dba0f6268 by Valentin Rusu.
Committed on 15/08/2015 at 22:02.
Pushed by vrusu into branch 'master'.
Starting to implement createCollection
M +1 -0 src/runtime/ksecrets_store/CMakeLists.txt
M +153 -24 src/runtime/ksecrets_store/ksecrets_crypt.cpp
M +52 -18 src/runtime/ksecrets_store/ksecrets_data.cpp
M +24 -9 src/runtime/ksecrets_store/ksecrets_data.h
M +43 -2 src/runtime/ksecrets_store/ksecrets_file.cpp
M +14 -1 src/runtime/ksecrets_store/ksecrets_file.h
M +9 -3 src/runtime/ksecrets_store/ksecrets_store.cpp
M +1 -0 src/runtime/ksecrets_store/ksecrets_store_p.h
http://commits.kde.org/ksecrets/58c491477506a1fe6adbd04412da565dba0f6268
diff --git a/src/runtime/ksecrets_store/CMakeLists.txt \
b/src/runtime/ksecrets_store/CMakeLists.txt index 5805ce7..1236bf0 100644
--- a/src/runtime/ksecrets_store/CMakeLists.txt
+++ b/src/runtime/ksecrets_store/CMakeLists.txt
@@ -9,6 +9,7 @@ ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX KSECRETS_BACKEND
PACKAGE_VERSION_FILE \
"${CMAKE_CURRENT_BINARY_DIR}/KF5SecretsStoreConfigVersion.cmake")
set(ksecrets_store_SRC
+ ksecrets_data.cpp
ksecrets_file.cpp
ksecrets_crypt.cpp
ksecrets_credentials.cpp
diff --git a/src/runtime/ksecrets_store/ksecrets_crypt.cpp \
b/src/runtime/ksecrets_store/ksecrets_crypt.cpp index 0af3e1f..a5a32f8 100644
--- a/src/runtime/ksecrets_store/ksecrets_crypt.cpp
+++ b/src/runtime/ksecrets_store/ksecrets_crypt.cpp
@@ -20,6 +20,7 @@
*/
#include "defines.h"
+#include "ksecrets_crypt.h"
#include <sys/types.h>
#include <errno.h>
@@ -51,7 +52,8 @@ int kss_init_gcry()
gcry_error_t gcryerr;
gcryerr = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0);
if (gcryerr != 0) {
- syslog(KSS_LOG_ERR, "ksecrets_store: cannot get secure memory: %d", gcryerr);
+ syslog(KSS_LOG_ERR, "ksecrets_store: cannot get secure memory: %d",
+ gcryerr);
return 0;
}
@@ -60,59 +62,79 @@ int kss_init_gcry()
return 1;
}
-int kss_derive_keys(const char* salt, const char* password, char* encryption_key, char* \
mac_key, size_t keySize) +int kss_derive_keys(const char* salt, const char* password,
+ char* encryption_key, char* mac_key, size_t keySize)
{
gpg_error_t gcryerr;
syslog(KSS_LOG_INFO, "kss_set_credentials: attempting keys generation");
if (0 == password) {
- syslog(KSS_LOG_INFO, "NULL password given. ksecrets will not be available.");
+ syslog(KSS_LOG_INFO,
+ "NULL password given. ksecrets will not be available.");
return FALSE;
}
/* generate both encryption and MAC key in one go */
char keys[2 * keySize];
- gcryerr = gcry_kdf_derive(password, strlen(password), GCRY_KDF_ITERSALTED_S2K, \
GCRY_MD_SHA512, salt, 8, KSECRETS_ITERATIONS, 2 * keySize, keys); + gcryerr
+ = gcry_kdf_derive(password, strlen(password), GCRY_KDF_ITERSALTED_S2K,
+ GCRY_MD_SHA512, salt, 8, KSECRETS_ITERATIONS, 2 * keySize, keys);
if (gcryerr) {
- syslog(KSS_LOG_ERR, "key derivation failed: code 0x%0x: %s/%s", gcryerr, \
gcry_strsource(gcryerr), gcry_strerror(gcryerr)); + syslog(KSS_LOG_ERR, "key derivation \
failed: code 0x%0x: %s/%s", + gcryerr, gcry_strsource(gcryerr), \
gcry_strerror(gcryerr)); return FALSE;
}
memcpy(encryption_key, keys, keySize);
memcpy(mac_key, keys + keySize, keySize);
- syslog(KSS_LOG_INFO, "successuflly generated ksecrets keys from user password.");
+ syslog(KSS_LOG_INFO,
+ "successuflly generated ksecrets keys from user password.");
return TRUE;
}
-int kss_store_keys(const char* encryption_key, const char* mac_key, size_t keySize)
+int kss_store_keys(
+ const char* encryption_key, const char* mac_key, size_t keySize)
{
key_serial_t ks;
const char* key_name = get_keyname_encrypting();
- ks = add_key("user", key_name, encryption_key, keySize, KEY_SPEC_SESSION_KEYRING);
+ ks = add_key(
+ "user", key_name, encryption_key, keySize, KEY_SPEC_SESSION_KEYRING);
if (-1 == ks) {
- syslog(KSS_LOG_ERR, "ksecrets: cannot store encryption key in kernel keyring: errno=%d \
(%m)", errno); + syslog(KSS_LOG_ERR, "ksecrets: cannot store encryption key in kernel "
+ "keyring: errno=%d (%m)",
+ errno);
return FALSE;
}
- syslog(KSS_LOG_DEBUG, "ksecrets: encrpyting key now in kernel keyring with id %d and desc \
%s", ks, key_name); + syslog(KSS_LOG_DEBUG, "ksecrets: encrpyting key now in kernel keyring \
" + "with id %d and desc %s",
+ ks, key_name);
key_name = get_keyname_mac();
- ks = add_key("user", key_name, mac_key, keySize, KEY_SPEC_SESSION_KEYRING);
+ ks = add_key(
+ "user", key_name, mac_key, keySize, KEY_SPEC_SESSION_KEYRING);
if (-1 == ks) {
- syslog(KSS_LOG_ERR, "ksecrets: cannot store mac key in kernel keyring: errno=%d (%m)", \
errno); + syslog(KSS_LOG_ERR,
+ "ksecrets: cannot store mac key in kernel keyring: errno=%d (%m)",
+ errno);
return FALSE;
}
- syslog(KSS_LOG_DEBUG, "ksecrets: mac key now in kernel keyring with id %d and desc %s", \
ks, key_name); + syslog(KSS_LOG_DEBUG,
+ "ksecrets: mac key now in kernel keyring with id %d and desc %s", ks,
+ key_name);
return TRUE;
}
-int kss_set_credentials(const std::string &password, const char *salt)
+int kss_set_credentials(const std::string& password, const char* salt)
{
- // FIXME this should be adjusted on platforms where kernel keyring is not available and \
store the keys elsewhere + // FIXME this should be adjusted on platforms where kernel \
keyring is not + // available and store the keys elsewhere
char encryption_key[KSECRETS_KEYSIZE];
char mac_key[KSECRETS_KEYSIZE];
- auto res = kss_derive_keys(salt, password.c_str(), encryption_key, mac_key, \
KSECRETS_KEYSIZE);
- if (res) return res;
+ auto res = kss_derive_keys(
+ salt, password.c_str(), encryption_key, mac_key, KSECRETS_KEYSIZE);
+ if (res)
+ return res;
return kss_store_keys(encryption_key, mac_key, KSECRETS_KEYSIZE);
}
@@ -120,26 +142,32 @@ int kss_set_credentials(const std::string &password, const char *salt)
int kss_keys_already_there()
{
key_serial_t key;
- key = request_key("user", get_keyname_encrypting(), 0, KEY_SPEC_SESSION_KEYRING);
+ key = request_key(
+ "user", get_keyname_encrypting(), 0, KEY_SPEC_SESSION_KEYRING);
if (-1 == key) {
- syslog(KSS_LOG_DEBUG, "request_key failed with errno %d (%m), so assuming ksecrets not \
yet loaded", errno); + syslog(KSS_LOG_DEBUG, "request_key failed with errno %d (%m), so \
" + "assuming ksecrets not yet loaded",
+ errno);
return FALSE;
}
syslog(KSS_LOG_DEBUG, "ksecrets: keys already in keyring");
return TRUE;
}
-long kss_read_key(const char *keyName, char* buffer, size_t bufferSize)
+long kss_read_key(const char* keyName, char* buffer, size_t bufferSize)
{
key_serial_t key;
key = request_key("user", keyName, 0, KEY_SPEC_SESSION_KEYRING);
if (-1 == key) {
- syslog(KSS_LOG_DEBUG, "request_key failed with errno %d (%m) when reading MAC key %s", \
errno, keyName); + syslog(KSS_LOG_DEBUG,
+ "request_key failed with errno %d (%m) when reading MAC key %s",
+ errno, keyName);
return -1;
}
auto bytes = keyctl_read(key, buffer, bufferSize);
if (bytes == -1) {
- syslog(KSS_LOG_ERR, "error reading key %s contents from the keyring", keyName);
+ syslog(KSS_LOG_ERR, "error reading key %s contents from the keyring",
+ keyName);
return -1;
}
if ((size_t)bytes > bufferSize) {
@@ -148,13 +176,114 @@ long kss_read_key(const char *keyName, char* buffer, size_t bufferSize)
return 0; // key contents correctly transffered into the buffer
}
-long kss_read_mac_key(char *buffer, size_t bufferSize)
+long kss_read_mac_key(char* buffer, size_t bufferSize)
{
return kss_read_key(get_keyname_mac(), buffer, bufferSize);
}
-long kss_read_encrypting_key(char *buffer, size_t bufferSize)
+long kss_read_encrypting_key(char* buffer, size_t bufferSize)
{
return kss_read_key(get_keyname_encrypting(), buffer, bufferSize);
}
+#define ERRNO(cryres) gcry_err_code_to_errno(gcry_err_code(cryres))
+
+long kss_cipher_setup(gcry_cipher_hd_t* hd, const void* iv, size_t liv)
+{
+ // FIXME perhaps all this initialization stuff could only be done once,
+ // when password is setup
+ auto cryres
+ = gcry_cipher_open(hd, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 0);
+ if (cryres) {
+ syslog(KSS_LOG_ERR, "ksecrets: gcry_cipher_open returned error %d",
+ cryres);
+ return ERRNO(cryres);
+ }
+ cryres = gcry_cipher_setiv(*hd, iv, liv);
+ if (cryres) {
+ syslog(KSS_LOG_ERR, "ksecrets: gcry_cipher_setif returned error %d",
+ cryres);
+ return ERRNO(cryres);
+ }
+ char encryptingKey[KSECRETS_KEYSIZE];
+ auto keyres = kss_read_encrypting_key(
+ encryptingKey, sizeof(encryptingKey) / sizeof(encryptingKey[0]));
+ if (!keyres) {
+ syslog(
+ KSS_LOG_ERR, "ksecrets: encrypting key not found in the keyring");
+ return keyres;
+ }
+ cryres = gcry_cipher_setkey(
+ *hd, encryptingKey, sizeof(encryptingKey) / sizeof(encryptingKey[0]));
+ if (cryres) {
+ syslog(
+ KSS_LOG_ERR, "ksecrets: gcry_cipher_setkey returned %d", cryres);
+ return ERRNO(cryres);
+ }
+ return 0;
+}
+
+long kss_encrypt_buffer(unsigned char* out, size_t lout, const void* iv,
+ size_t liv, const unsigned char* in, size_t lin)
+{
+ gcry_cipher_hd_t hd;
+ auto cryres = kss_cipher_setup(&hd, iv, liv);
+ if (cryres)
+ return cryres; // error already logged
+ cryres = gcry_cipher_encrypt(hd, out, lout, in, lin);
+ if (cryres) {
+ syslog(KSS_LOG_ERR, "ksecrets: gcry_cipher_encrypt returned %ld",
+ cryres);
+ return ERRNO(cryres);
+ }
+ return 0;
+}
+
+long kss_decrypt_buffer(unsigned char* out, size_t lout, const void* iv,
+ size_t liv, const unsigned char* in, size_t lin)
+{
+ gcry_cipher_hd_t hd;
+ auto cryres = kss_cipher_setup(&hd, iv, liv);
+ if (cryres)
+ return cryres; // error already logged
+ cryres = gcry_cipher_decrypt(hd, out, lout, in, lin);
+ if (cryres) {
+ syslog(KSS_LOG_ERR, "ksecrets: gcry_cipher_decrypt returned %ld",
+ cryres);
+ return ERRNO(cryres);
+ }
+ return 0;
+}
+
+bool CryptBuffer::resize(size_t rlen)
+{
+ if (rlen <= len_) {
+ return false; // if less bytes, we cannot copy; if same, why resize?
+ }
+ CryptBuffer oldBuffer(std::move(*this));
+ len_ = (rlen / cipherBlockLen_ + 1) * cipherBlockLen_;
+ data_ = new unsigned char[len_];
+ if (data_ && oldBuffer.len_) {
+ memmove(data_, oldBuffer.data_, oldBuffer.len_);
+ return true;
+ }
+ return false;
+}
+
+void CryptBuffer::empty()
+{
+ delete[] data_, data_ = nullptr;
+ len_ = 0;
+}
+
+bool CryptBuffer::allocate(size_t rlen)
+{
+ empty();
+ data_ = new unsigned char[rlen];
+ if (data_ == nullptr) {
+ return false;
+ }
+ len_ = rlen;
+ return true;
+}
+// vim: tw=220:ts=4
diff --git a/src/runtime/ksecrets_store/ksecrets_data.cpp \
b/src/runtime/ksecrets_store/ksecrets_data.cpp index 4998fcd..61a8f64 100644
--- a/src/runtime/ksecrets_store/ksecrets_data.cpp
+++ b/src/runtime/ksecrets_store/ksecrets_data.cpp
@@ -23,32 +23,66 @@
#include <unistd.h>
+long kss_encrypt_buffer(unsigned char* out, size_t lout, const void* iv,
+ size_t liv, const unsigned char* in, size_t lin);
+long kss_decrypt_buffer(unsigned char* out, size_t lout, const void* iv,
+ size_t liv, const unsigned char* in, size_t lin);
+char* kss_alloc_crypt_buffer(size_t rlen);
+
SecretsEntity::SecretsEntity()
- : size_(0)
- , state_(Empty)
- , encrypted_(nullptr)
- , unencrypted_(nullptr)
+ : state_(State::Empty)
{
}
-SecretsEntity::~SecretsEntity()
+
+SecretsEntity::~SecretsEntity() {}
+
+// TODO refactor this when encrypting plugins will be put in place
+// the KSecretsFile should place the IV in the plugin structure instead of
+// this class
+const char* iv = nullptr;
+size_t liv = KSecretsFile::IV_SIZE;
+
+bool SecretsEntity::read(KSecretsFile& file)
{
- if (encrypted_) {
- ::free(encrypted_);
- encrypted_ = nullptr;
+ if (iv == nullptr) {
+ iv = file.iv();
}
- if (unencrypted_) {
- ::free(unencrypted_);
- unencrypted_ = nullptr;
+
+ size_t s;
+ if (!file.read(s)) {
+ return false;
}
-}
-bool SecretsEntity::read(KSecretsFile& file)
-{
- if (!file.read(size_)) {
+ if (!encrypted_.allocate(s)) {
return false;
}
- encrypted_ = ::malloc(res);
- if (encrypted_ == nullptr) {
+ return file.read(encrypted_.data_,
+ encrypted_.len_); // beware not to specify encrypted.size_ here
+}
+
+bool SecretsEntity::decrypt()
+{
+ if (isEmpty())
return false;
- }
+ if (unencrypted_.len_ > 0)
+ return true; // already decrpyted
+ if (encrypted_.len_ == 0)
+ return false; // what to decrypt?
+ unencrypted_.allocate(encrypted_.len_);
+ auto dres = kss_decrypt_buffer(unencrypted_.data_, unencrypted_.len_, iv,
+ liv, encrypted_.data_, encrypted_.len_);
+ return dres == 0;
+}
+
+bool SecretsEntity::encrypt()
+{
+ // TODO
+ return false;
+}
+
+bool SecretsEntity::write(KSecretsFile &) const
+{
+ // TODO
+ return false;
}
+// vim: tw=220:ts=4
diff --git a/src/runtime/ksecrets_store/ksecrets_data.h \
b/src/runtime/ksecrets_store/ksecrets_data.h index e5b8964..dca51f7 100644
--- a/src/runtime/ksecrets_store/ksecrets_data.h
+++ b/src/runtime/ksecrets_store/ksecrets_data.h
@@ -21,33 +21,48 @@
#ifndef KSECRETS_DATA_H
#define KSECRETS_DATA_H
+#include "ksecrets_crypt.h"
+
#include <cstdint>
#include <sys/types.h>
class KSecretsFile;
+/**
+ * @brief Elementary secret element
+ *
+ * TODO this class uses routines from ksecrets_crypt.cpp file to handle
+ * encrypting and decrypting of the files. It would be better to define some
+ * plugin architecture, allowing users specify different encryption methods.
+ */
struct SecretsEntity {
SecretsEntity();
SecretsEntity(const SecretsEntity&) = delete;
SecretsEntity(SecretsEntity&&) = delete;
virtual ~SecretsEntity();
- enum class State: std::uint8_t {
+ enum class State : std::uint8_t {
Empty = 0,
Encrypted = 0x01,
Decrypted = 0x02
};
- size_t size_;
- State state_;
- char* encrypted_;
- char* unencrypted_;
+ bool isEmpty() const noexcept { return state_ == State::Empty; }
+ bool isDecrypted() const noexcept
+ {
+ return (static_cast<std::uint8_t>(state_)
+ & static_cast<std::uint8_t>(State::Decrypted)) != 0;
+ }
- bool decrypt() noexcept;
- bool encrypt() noexcept;
+ virtual bool decrypt() noexcept;
+ virtual bool encrypt() noexcept;
- bool read(KSecretsFile&) noexcept;
- bool write(KSecretsFile&) const noexcept;
+ virtual bool read(KSecretsFile&) noexcept;
+ virtual bool write(KSecretsFile&) const noexcept;
+
+ State state_;
+ CryptBuffer encrypted_;
+ CryptBuffer unencrypted_;
};
struct SecretsCollection : public SecretsEntity {
diff --git a/src/runtime/ksecrets_store/ksecrets_file.cpp \
b/src/runtime/ksecrets_store/ksecrets_file.cpp index 7d91de3..c3dc275 100644
--- a/src/runtime/ksecrets_store/ksecrets_file.cpp
+++ b/src/runtime/ksecrets_store/ksecrets_file.cpp
@@ -37,6 +37,7 @@ KSecretsFile::KSecretsFile()
: file_(-1)
, locked_(false)
, empty_(true)
+ , eof_(false)
{
memset(&fileHead_, 0, sizeof(fileHead_));
}
@@ -105,6 +106,7 @@ bool KSecretsFile::readHeader()
if (eoftest == 0) {
// we are at EOF already, so file is empty
empty_ = true;
+ eof_ = true;
}
else {
if (-1 == lseek(file_, -bytes, SEEK_CUR)) {
@@ -139,8 +141,47 @@ int KSecretsFile::checkMAC() const
return -1;
}
-KSecretsFile::DirCollectionResult KSecretsFile::dirCollections() {
- return DirCollectionResult();
+bool KSecretsFile::read(size_t& s) { return read(&s, sizeof(s)); }
+
+bool KSecretsFile::read(void* buf, size_t len)
+{
+ if (eof_) return false;
+ auto rres = ::read(file_, buf, len);
+ if (rres < 0)
+ return setFailState(errno);
+ if (static_cast<size_t>(rres) < len)
+ return setEOF(); // are we @ EOF?
+ return true;
+}
+
+KSecretsFile::DirCollectionResult KSecretsFile::dirCollections()
+{
+ DirCollectionResult res;
+ res.first = false;
+ res.second = nullptr;
+
+ if (empty_) {
+ return res;
+ }
+
+ readDirectory();
+ decryptEntity(directory_);
+
+ if (directory_.isDecrypted()) {
+ res.first = true;
+ res.second = &directory_;
+ }
+
+ return res;
}
+bool KSecretsFile::readDirectory()
+{
+ if (empty_)
+ return false; // file is empty, don't event attempt read
+ return directory_.read(*this);
+}
+
+bool KSecretsFile::decryptEntity(SecretsEntity& entity) { return entity.decrypt(); }
+
// vim: tw=220:ts=4
diff --git a/src/runtime/ksecrets_store/ksecrets_file.h \
b/src/runtime/ksecrets_store/ksecrets_file.h index a929cca..5ed8c79 100644
--- a/src/runtime/ksecrets_store/ksecrets_file.h
+++ b/src/runtime/ksecrets_store/ksecrets_file.h
@@ -26,6 +26,9 @@
#include <memory>
#include <list>
+/**
+ * @brief This is the secrets file format handling class
+ */
class KSecretsFile {
public:
KSecretsFile();
@@ -46,6 +49,7 @@ public:
bool readHeader() noexcept;
bool checkMagic() noexcept;
const char* salt() const noexcept { return fileHead_.salt_; }
+ const char* iv() const noexcept { return fileHead_.iv_; }
int checkMAC() const noexcept;
bool read(void* buf, size_t count);
bool read(size_t&);
@@ -54,11 +58,18 @@ public:
DirCollectionResult dirCollections() noexcept;
private:
- bool setFailState(int err, bool retval = false)
+ bool setFailState(int err, bool retval = false) noexcept
{
errno_ = err;
return retval; // wo do like this so this function could end other methods with an \
elegant return setFailState(errno); }
+ bool setEOF() noexcept {
+ eof_ = true;
+ return false; // this work the same as setFailState
+ }
+ bool readDirectory() noexcept;
+ bool decryptEntity(SecretsEntity&) noexcept;
+
using Entities = std::list<SecretsEntity*>;
std::string filePath_;
@@ -69,7 +80,9 @@ private:
bool empty_;
char fileMAC_[64];
Entities entities_;
+ CollectionDirectory directory_;
int errno_;
+ bool eof_;
};
#endif
diff --git a/src/runtime/ksecrets_store/ksecrets_store.cpp \
b/src/runtime/ksecrets_store/ksecrets_store.cpp index 9e3967b..8e4bf00 100644
--- a/src/runtime/ksecrets_store/ksecrets_store.cpp
+++ b/src/runtime/ksecrets_store/ksecrets_store.cpp
@@ -165,10 +165,16 @@ KSecretsStore::DirCollectionsResult \
KSecretsStorePrivate::dirCollections() return res;
}
-KSecretsStore::CreateCollectionResult KSecretsStore::createCollection(const char*) noexcept
+KSecretsStore::CreateCollectionResult KSecretsStore::createCollection(const char* collName) \
noexcept {
- // TODO
- return CreateCollectionResult();
+ return d->createCollection(collName);
+}
+
+KSecretsStore::CreateCollectionResult KSecretsStorePrivate::createCollection(const std::string \
&collName) noexcept +{
+ KSecretsStore::CreateCollectionResult res;
+
+ return res;
}
KSecretsStore::ReadCollectionResult KSecretsStore::readCollection(const char*) const noexcept
diff --git a/src/runtime/ksecrets_store/ksecrets_store_p.h \
b/src/runtime/ksecrets_store/ksecrets_store_p.h index 8dee77c..c8f8aaa 100644
--- a/src/runtime/ksecrets_store/ksecrets_store_p.h
+++ b/src/runtime/ksecrets_store/ksecrets_store_p.h
@@ -64,6 +64,7 @@ public:
KSecretsStore::SetupResult open(bool) noexcept;
int createFile(const std::string&) noexcept;
const char* salt() const noexcept;
+ KSecretsStore::CreateCollectionResult createCollection(const std::string&) noexcept;
KSecretsStore::DirCollectionsResult dirCollections() noexcept;
template <typename S> S setStoreStatus(S s) noexcept
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic