Exemple #1
0
/**
 * Compare 2 keys.
 *
 * The returned flags bit array has 1s (differ) or 0s (equal) for each key
 * meta info compared, that can be logically ORed using @c #keyswitch_t flags.
 * @link keyswitch_t::KEY_NAME KEY_NAME @endlink,
 * @link keyswitch_t::KEY_VALUE KEY_VALUE @endlink,
 * @link keyswitch_t::KEY_OWNER KEY_OWNER @endlink,
 * @link keyswitch_t::KEY_COMMENT KEY_COMMENT @endlink,
 * @link keyswitch_t::KEY_UID KEY_UID @endlink,
 * @link keyswitch_t::KEY_GID KEY_GID @endlink,
 * @link keyswitch_t::KEY_MODE KEY_MODE @endlink and
 *
 * @par A very simple example would be
 * @code
Key *key1, *key;
uint32_t changes;

// omited key1 and key2 initialization and manipulation

changes=keyCompare(key1,key2);

if (changes == 0) printf("key1 and key2 are identicall\n");

if (changes & KEY_VALUE)
	printf("key1 and key2 have different values\n");
 
if (changes & KEY_UID)
	printf("key1 and key2 have different UID\n");
 
 *
 * @endcode
 *
 * 
 * @par Example of very powerful specific Key lookup in a KeySet:
 * @code
KDB *handle = kdbOpen();
KeySet *ks=ksNew(0);
Key *base = keyNew ("user/sw/MyApp/something", KEY_END);
Key *current;
uint32_t match;
uint32_t interests;


kdbGetByName(handle, ks, "user/sw/MyApp", 0);

// we are interested only in key type and access permissions
interests=(KEY_TYPE | KEY_MODE);

ksRewind(ks);   // put cursor in the beginning
while ((curren=ksNext(ks))) {
	match=keyCompare(current,base);
	
	if ((~match & interests) == interests)
		printf("Key %s has same type and permissions of base key",keyName(current));

	// continue walking in the KeySet....
}

// now we want same name and/or value
interests=(KEY_NAME | KEY_VALUE);

// we don't really need ksRewind(), since previous loop achieved end of KeySet
ksRewind(ks);
while ((current=ksNext(ks))) {
	match=keyCompare(current,base);

	if ((~match & interests) == interests) {
		printf("Key %s has same name, value, and sync status
			of base key",keyName(current));
	}
	// continue walking in the KeySet....
}

keyDel(base);
ksDel(ks);
kdbClose (handle);
 * @endcode
 * 
 * @return a bit array pointing the differences
 * @param key1 first key
 * @param key2 second key
 * @see #keyswitch_t
 * @ingroup keytest
 */
keyswitch_t keyCompare(const Key *key1, const Key *key2)
{
	if (!key1 && !key2) return 0;
	if (!key1 || !key2) return KEY_NULL;

	keyswitch_t ret=0;
	ssize_t nsize1 = keyGetNameSize(key1);
	ssize_t nsize2 = keyGetNameSize(key2);
	const char *name1 = keyName(key1);
	const char *name2 = keyName(key2);
	const char *comment1 = keyComment(key1);
	const char *comment2 = keyComment(key2);
	const char *owner1 = keyOwner(key1);
	const char *owner2 = keyOwner(key2);
	const void *value1 = keyValue(key1);
	const void *value2 = keyValue(key2);
	ssize_t size1 = keyGetValueSize(key1);
	ssize_t size2 = keyGetValueSize(key2);


	if (keyGetUID(key1) != keyGetUID(key2))  ret|=KEY_UID;
	if (keyGetGID(key1) != keyGetGID(key2))  ret|=KEY_GID;
	if (keyGetMode(key1)!= keyGetMode(key2)) ret|=KEY_MODE;
	if (nsize1 != nsize2)              ret|=KEY_NAME;
	if (strcmp(name1, name2))          ret|=KEY_NAME;
	if (strcmp(comment1, comment2))    ret|=KEY_COMMENT;
	if (strcmp(owner1, owner2))        ret|=KEY_OWNER;
	if (size1 != size2)                ret|=KEY_VALUE;
	if (memcmp(value1, value2, size1)) ret|=KEY_VALUE;

	return ret;
}
Exemple #2
0
static void validateArrayRange (Key * parent, long validCount, Key * specKey)
{
	const Key * arrayRange = keyGetMeta (specKey, "array");
	if (arrayRange != NULL)
	{
		char * rangeString = elektraMalloc (keyGetValueSize (arrayRange));
		keyGetString (arrayRange, rangeString, keyGetValueSize (arrayRange));
		char * delimPtr = strchr (rangeString, '-');
		long min = 0;
		long max = 0;
		if (delimPtr)
		{
			char * maxString = delimPtr + 1;
			*delimPtr = '\0';
			char * minString = rangeString;
			min = atoi (minString);
			max = atoi (maxString);
		}
		else
		{
			min = max = atoi (rangeString);
		}
		if (validCount < min || validCount > max)
		{
			char buffer[MAX_CHARS_IN_LONG + 1];
			snprintf (buffer, sizeof (buffer), "%ld", validCount);
			keySetMeta (parent, "conflict/range", buffer);
		}
		elektraFree (rangeString);
	}
}
static void test_enc_and_dec_with_null()
{
	elektraCryptoHandle *handle;
	KeySet *config;
	Key *errorKey = keyNew(KEY_END);

	Key *k = keyNew("user/plugins/crypto/gcrypt/test-enc-dec-null", KEY_END);
	keySetBinary(k, 0, 0);
	succeed_if( keyGetValueSize(k) == 0, "key is not NULL");

	getWorkingConfiguration(&config);
	succeed_if( elektraCryptoInit(errorKey) == 1, "crypto initialization failed" );

	// 1. encrypt
	succeed_if( elektraCryptoHandleCreate(&handle, config, errorKey) == 1, "handle initialization with compliant config failed" );
	succeed_if( elektraCryptoEncrypt(handle, k, errorKey) == 1, "encryption failed" );
	elektraCryptoHandleDestroy(handle);

	// 2. decrypt
	succeed_if( elektraCryptoHandleCreate(&handle, config, errorKey) == 1, "handle initialization with compliant config failed" );
	succeed_if( elektraCryptoDecrypt(handle, k, errorKey) == 1, "decryption failed" );
	elektraCryptoHandleDestroy(handle);

	// 3. check result
	succeed_if( keyGetValueSize(k) == 0, "key is not NULL");

	keyDel(k);
	keyDel(errorKey);
	ksDel(config);
	elektraCryptoTeardown();
}
Exemple #4
0
char * elektraMetaArrayToString (Key * key, const char * metaName, const char * delim)
{
	char * result = NULL;
	Key * lookupElem = keyDup (keyGetMeta (key, metaName));
	keyAddBaseName (lookupElem, "#0");
	Key * elem = (Key *)keyGetMeta (key, keyName (lookupElem));
	if (elem != NULL)
	{
		elektraRealloc ((void **)&result, keyGetValueSize (elem));
		snprintf (result, keyGetValueSize (elem), "%s", keyString (elem));
	}
	elektraArrayIncName (lookupElem);
	elem = (Key *)keyGetMeta (key, keyName (lookupElem));
	while (elem != NULL)
	{
		elektraRealloc ((void **)&result,
				elektraStrLen (result) + keyGetValueSize (elem) + 1); // String (incl. +2 times \0) + delimiter + whitespace
		strcat (result, delim);
		strcat (result, keyString (elem));
		elektraArrayIncName (lookupElem);
		elem = (Key *)keyGetMeta (key, keyName (lookupElem));
	}
	keyDel (lookupElem);
	return result;
}
Exemple #5
0
int elektraIconvSet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	Key * cur;

	if (!kdbbNeedsUTF8Conversion (handle)) return 0;

	ksRewind (returned);

	while ((cur = ksNext (returned)) != 0)
	{
		if (keyIsString (cur))
		{
			/* String or similar type of value */
			size_t convertedDataSize = keyGetValueSize (cur);
			char * convertedData = elektraMalloc (convertedDataSize);

			memcpy (convertedData, keyString (cur), keyGetValueSize (cur));
			if (kdbbUTF8Engine (handle, UTF8_TO, &convertedData, &convertedDataSize))
			{
				ELEKTRA_SET_ERRORF (46, parentKey,
						    "Could not convert string %s, got result %s,"
						    " encoding settings are from %s to %s (but swapped for write)",
						    keyString (cur), convertedData, getFrom (handle), getTo (handle));
				elektraFree (convertedData);
				return -1;
			}
			keySetString (cur, convertedData);
			elektraFree (convertedData);
		}
		const Key * meta = keyGetMeta (cur, "comment");
		if (meta)
		{
			/* String or similar type of value */
			size_t convertedDataSize = keyGetValueSize (meta);
			char * convertedData = elektraMalloc (convertedDataSize);

			memcpy (convertedData, keyString (meta), keyGetValueSize (meta));
			if (kdbbUTF8Engine (handle, UTF8_TO, &convertedData, &convertedDataSize))
			{
				ELEKTRA_SET_ERRORF (46, parentKey,
						    "Could not convert string %s, got result %s,"
						    " encodings settings are from %s to %s (but swapped for write)",
						    keyString (meta), convertedData, getFrom (handle), getTo (handle));
				elektraFree (convertedData);
				return -1;
			}
			keySetMeta (cur, "comment", convertedData);
			elektraFree (convertedData);
		}
	}

	return 1; /* success */
}
Exemple #6
0
static int handleOutOfRangeConflict (Key * parentKey, Key * key, Key * specKey, Key * conflictMeta, OnConflict onConflict)
{
	int ret = 0;
	switch (onConflict)
	{
	case ERROR:
		ELEKTRA_SET_ERRORF (142, parentKey, "%s has invalid number of members: %s. Expected: %s\n", keyName (key),
				    keyString (conflictMeta), keyString (keyGetMeta (specKey, "array")));
		ret = -1;
		break;
	case WARNING:
		ELEKTRA_ADD_WARNINGF (143, parentKey, "%s has invalid number of members: %s. Expected: %s\n", keyName (key),
				      keyString (conflictMeta), keyString (keyGetMeta (specKey, "array")));
		break;
	case INFO:
	{
		const char * infoString = "%s has invalid number of member: %s. Expected: %s";
		const size_t len = elektraStrLen (infoString) + elektraStrLen (keyName (key)) + MAX_CHARS_IN_LONG +
				   keyGetValueSize (keyGetMeta (specKey, "array")) - 2;
		char * buffer = elektraMalloc (len);
		snprintf (buffer, len, infoString, keyName (key), keyString (conflictMeta), keyString (keyGetMeta (specKey, "array")));
		elektraMetaArrayAdd (key, "logs/spec/info", buffer);
		elektraFree (buffer);
	}
	break;
	case IGNORE:

		break;
	}
	return ret;
}
Exemple #7
0
/**
 * @internal
 *
 * Set raw  data as the value of a key.
 * If NULL pointers are passed, key value is cleaned.
 * This method will not change or set the key type, and should only
 * be used internally in elektra.
 *
 * @param key the key object to work with
 * @param newBinary array of bytes to set as the value
 * @param dataSize number bytes to use from newBinary, including the final NULL
 * @return The number of bytes actually set in internal buffer.
 * @retval 1 if it was a string which was deleted
 * @retval 0 if it was a binary which was deleted
 * @see keySetType(), keySetString(), keySetBinary()
 * @ingroup keyvalue
 */
ssize_t keySetRaw(Key *key, const void *newBinary, size_t dataSize)
{
    if (!key) return -1;
    if (key->flags & KEY_FLAG_RO_VALUE) return -1;

    if (!dataSize || !newBinary)
    {
        if (key->data.v) {
            elektraFree (key->data.v);
            key->data.v=0;
        }
        key->dataSize = 0;
        set_bit(key->flags, KEY_FLAG_SYNC);
        if (keyIsBinary(key)) return 0;
        return 1;
    }

    key->dataSize=dataSize;
    if (key->data.v)
    {
        char *p=0;
        p=realloc(key->data.v,key->dataSize);
        if (0==p) return -1;
        key->data.v=p;
    } else {
        char *p=elektraMalloc(key->dataSize);
        if (0==p) return -1;
        key->data.v=p;
    }


    memcpy(key->data.v,newBinary,key->dataSize);
    set_bit(key->flags, KEY_FLAG_SYNC);
    return keyGetValueSize (key);
}
static void test_keyGetString (const size_t storagePlugin, const char * tmpFile)
{
	Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
	open_storage_plugin (storagePlugin);
	Plugin * plugin = plugins[storagePlugin];

	KeySet * ks = metaTestKeySet ();
	const char * name = "user/tests/storage/specialkey";
	const char * value = "special value";
	size_t realValueSize = elektraStrLen (value);
	Key * key = keyNew (name, KEY_VALUE, value, KEY_END);
	ksAppendKey (ks, key);
	succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
	succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");

	Key * found = ksLookupByName (ks, name, 0);
	succeed_if (found, "did not find key");

	ssize_t apiValueSize = keyGetValueSize (found);
	char * apiString = elektraMalloc (apiValueSize);
	succeed_if (keyGetString (found, apiString, apiValueSize) == (ssize_t) realValueSize, "Key string has wrong size");

	succeed_if (elektraStrNCmp (value, apiString, realValueSize) == 0, "Key string value is wrong");

	elektraFree (apiString);
	keyDel (parentKey);
	ksDel (ks);
	closeStoragePlugin (storagePlugin);
}
Exemple #9
0
static KeySet * getGlobKeys (Key * parentKey, KeySet * keys, enum GlobDirection direction)
{
	KeySet * glob = ksNew (0, KS_END);
	Key * k = 0;
	size_t parentsize = keyGetNameSize (parentKey);

	Key * userGlobConfig = 0;
	Key * systemGlobConfig = 0;
	Key * userDirGlobConfig = 0;
	Key * systemDirGlobConfig = 0;

	userGlobConfig = keyNew ("user/glob", KEY_END);
	systemGlobConfig = keyNew ("system/glob", KEY_END);
	switch (direction)
	{
	case GET:
		userDirGlobConfig = keyNew ("user/glob/get", KEY_END);
		systemDirGlobConfig = keyNew ("system/glob/get", KEY_END);
		break;
	case SET:
		userDirGlobConfig = keyNew ("user/glob/set", KEY_END);
		systemDirGlobConfig = keyNew ("system/glob/set", KEY_END);
		break;
	}

	while ((k = ksNext (keys)) != 0)
	{
		/* use only glob keys for the current direction */
		if (keyIsDirectBelow (userGlobConfig, k) || keyIsDirectBelow (systemGlobConfig, k) ||
		    keyIsDirectBelow (userDirGlobConfig, k) || keyIsDirectBelow (systemDirGlobConfig, k))
		{
			keySetMeta (k, "glob/flags", getGlobFlags (keys, k));

			/* Look if we have a string */
			size_t valsize = keyGetValueSize (k);
			if (valsize < 2) continue;

			/* We now know we want that key.
			 Dup it to not change the configuration. */
			Key * ins = keyDup (k);
			/* Now look if we want cascading for the key */
			if (keyString (k)[0] == '/')
			{
				char * newstring = elektraMalloc (valsize + parentsize);
				strcpy (newstring, keyName (parentKey));
				strcat (newstring, keyString (k));
				keySetString (ins, newstring);
				elektraFree (newstring);
			}
			ksAppendKey (glob, ins);
		}
	}

	keyDel (userGlobConfig);
	keyDel (systemGlobConfig);
	keyDel (userDirGlobConfig);
	keyDel (systemDirGlobConfig);

	return glob;
}
Exemple #10
0
/** Reads the value of the key and decodes all escaping
  * codes into the buffer.
  * @pre the buffer needs to be as large as value's size.
  * @param cur the key holding the value to decode
  * @param buf the buffer to write to
  */
void elektraHexcodeDecode (Key * cur, CHexData * hd)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = keyValue (cur);

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		char c = val[in];
		char * n = hd->buf + out;

		if (c == hd->escape)
		{
			in += 2; /* Advance twice (2 hex numbers) */
			char first = val[in - 1];
			char second = val[in];
			int res;

			res = elektraHexcodeConvFromHex (second);
			res += elektraHexcodeConvFromHex (first) * 16;
			*n = res & 255;
		}
		else
		{
			*n = c;
		}
		++out; /* Only one char is written */
	}

	hd->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, hd->buf, out + 1);
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForDecryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	gcry_error_t gcry_err;
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE];
	kdb_octet_t * saltBuffer = NULL;
	kdb_unsigned_long_t saltBufferLen = 0;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// get the salt
	if (CRYPTO_PLUGIN_FUNCTION (getSaltFromPayload) (errorKey, k, &saltBuffer, &saltBufferLen) != 1)
	{
		return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromPayload)()
	}

	// get the iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// derive the cryptographic key and the IV
	if ((gcry_err = gcry_kdf_derive (keyValue (masterKey), keyGetValueSize (masterKey), GCRY_KDF_PBKDF2, GCRY_MD_SHA512, saltBuffer,
					 saltBufferLen, iterations, KEY_BUFFER_SIZE, keyBuffer)))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to restore the cryptographic key for decryption because: %s", gcry_strerror (gcry_err));
		return -1;
	}

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_GCRY_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_GCRY_KEYSIZE, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE);
	return 1;
}
Exemple #12
0
/**
 * Get the key comment.
 *
 * @section comment Comments
 *
 * A Key comment is description for humans what this key is for. It may be a
 * textual explanation of valid values, when and why a user or administrator
 * changed the key or any other text that helps the user or administrator related
 * to that key.
 *
 * Don't depend on a comment in your program. A user is
 * always allowed to remove or change it in any way he wants to. But you are
 * allowed or even encouraged to always show the content of the comment
 * to the user and allow him to change it.
 *
 * @param key the key object to work with
 * @param returnedComment pre-allocated memory to copy the comments to
 * @param maxSize number of bytes that will fit returnedComment
 * @return the number of bytes actually copied to @p returnedString, including
 * 	final NULL
 * @retval 1 if the string is empty
 * @retval -1 on NULL pointer
 * @retval -1 if maxSize is 0, not enough to store the comment or when larger then SSIZE_MAX
 * @see keyGetCommentSize(), keySetComment()
 */
ssize_t keyGetComment (const Key * key, char * returnedComment, size_t maxSize)
{
	const char * comment;
	size_t commentSize;
	if (!key) return -1;

	if (!maxSize) return -1;
	if (!returnedComment) return -1;
	if (maxSize > SSIZE_MAX) return -1;

	comment = keyValue (keyGetMeta (key, "comment"));
	commentSize = keyGetValueSize (keyGetMeta (key, "comment"));

	if (!comment)
	{
		/*errno=KDB_ERR_NODESC;*/
		returnedComment[0] = 0;
		return 1;
	}

	strncpy (returnedComment, comment, maxSize);
	if (maxSize < commentSize)
	{
		/*errno=KDB_ERR_TRUNC;*/
		return -1;
	}
	return commentSize;
}
Exemple #13
0
static void elektraDropCurrentKey (KeySet * ks, Key * warningKey, const Backend * curHandle, const char * msg)
{
	const Key * k = ksCurrent (ks);

	const size_t sizeOfStaticText = 100;
	char * warningMsg = elektraMalloc (keyGetNameSize (curHandle->mountpoint) + keyGetValueSize (curHandle->mountpoint) +
					   keyGetNameSize (k) + strlen (msg) + sizeOfStaticText);
	strcpy (warningMsg, "drop key ");
	const char * name = keyName (k);
	if (name)
	{
		strcat (warningMsg, name);
	}
	else
	{
		strcat (warningMsg, "(no name)");
	}
	strcat (warningMsg, " not belonging to ");
	strcat (warningMsg, keyName (curHandle->mountpoint));
	strcat (warningMsg, " with name ");
	strcat (warningMsg, keyString (curHandle->mountpoint));
	strcat (warningMsg, " because ");
	strcat (warningMsg, msg);
	ELEKTRA_ADD_WARNING (79, warningKey, warningMsg);
	elektraFree (warningMsg);
	cursor_t c = ksGetCursor (ks);
	keyDel (elektraKsPopAtCursor (ks, c));
	ksSetCursor (ks, c);
	elektraKsPrev (ks); // next ksNext() will point correctly again
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForDecryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE];
	kdb_octet_t * saltBuffer = NULL;
	kdb_unsigned_long_t saltBufferLen = 0;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// get the salt
	if (CRYPTO_PLUGIN_FUNCTION (getSaltFromPayload) (errorKey, k, &saltBuffer, &saltBufferLen) != 1)
	{
		return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromPayload)()
	}

	// get the iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// derive the cryptographic key and the IV
	pthread_mutex_lock (&mutex_ssl);
	if (!PKCS5_PBKDF2_HMAC_SHA1 (keyValue (masterKey), keyGetValueSize (masterKey), saltBuffer, saltBufferLen, iterations,
				     KEY_BUFFER_SIZE, keyBuffer))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to restore the cryptographic key for decryption. Libcrypto returned the error code: %lu",
				    ERR_get_error ());
		pthread_mutex_unlock (&mutex_ssl);
		return -1;
	}
	pthread_mutex_unlock (&mutex_ssl);

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_SSL_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_SSL_KEYSIZE, ELEKTRA_CRYPTO_SSL_BLOCKSIZE);
	return 1;
}
Exemple #15
0
/** Reads the value of the key and encodes it in
  * c-style in the buffer.
  *
  * @param cur the key which value is to encode
  * @param buf the buffer
  * @pre the buffer needs to have thrice as much space as the value's size
  */
void elektraHexcodeEncode (Key * cur, CHexData * hd)
{
	size_t valsize = keyGetValueSize (cur);
	const char * val = keyValue (cur);

	if (!val) return;

	size_t out = 0;
	for (size_t in = 0; in < valsize - 1; ++in)
	{
		unsigned char c = val[in];

		// need to encode char?
		if (hd->hd[c & 255])
		{
			hd->buf[out] = hd->escape;
			out++;
			hd->buf[out] = elektraHexcodeConvToHex (c / 16);
			out++;
			hd->buf[out] = elektraHexcodeConvToHex (c % 16);
			out++;
		}
		else
		{
			// just copy one character
			hd->buf[out] = val[in];
			// advance out cursor
			out++;
		}
	}

	hd->buf[out] = 0; // null termination for keyString()

	keySetRaw (cur, hd->buf, out + 1);
}
Exemple #16
0
// TODO: this is very similar to elektraKeyAppendMetaLine in keytometa
static int elektraKeyAppendLine (Key *target, const char *line)
{
	if (!target) return 0;
	if (!line) return 0;


	char *buffer = elektraMalloc (keyGetValueSize(target) + strlen (line) + 1);
	if (!buffer) return 0;

	keyGetString(target, buffer, keyGetValueSize(target));
	strcat (buffer, "\n");
	strncat (buffer, line, strlen (line));

	keySetString(target, buffer);
	elektraFree (buffer);
	return keyGetValueSize(target);
}
Exemple #17
0
/**
 * @brief Builds together a format string by the plugin's configuration
 *
 * @param handle to plugin
 * @param first format string for key
 * @param second format string for value
 *
 * @return newly allocated format (to be freed with elektraFree);
 */
static char * getFormat (Plugin * handle, const char * first, const char * second)
{
	char * format;
	Key * key = ksLookupByName (elektraPluginGetConfig (handle), "/format", 0);
	if (!key)
	{
		format = elektraStrDup ("%s = %s\n");
	}
	else
	{
		const size_t maxFactor = 2; // at maximum every char is a %, %% -> %%%%
		const size_t newLineAtEnd = 2;
		const size_t userFormatSize = keyGetValueSize (key);
		format = elektraMalloc (userFormatSize * maxFactor + newLineAtEnd);

		const char * userFormat = keyString (key);
		int gotPercent = 0;
		size_t j = 0;
		for (size_t i = 0; i < userFormatSize; ++i, ++j)
		{
			const char c = userFormat[i];
			if (gotPercent)
			{
				if (c == '%')
				{
					// escaped %% -> %%%%
					format[j++] = '%';
					format[j++] = '%';
					format[j] = '%';
				}
				else
				{
					// single % -> %s
					format[j++] = 's';
					format[j] = c;
				}
				gotPercent = 0;
			}
			else if (c == '%')
			{
				format[j] = c;
				gotPercent = 1;
			}
			else
			{
				format[j] = c;
			}
		}
		--j; // discard null byte that is already there
		ELEKTRA_ASSERT (format[j] == '\0', "should be null byte at end of string but was %c", format[j]);
		format[j++] = '\n';
		format[j] = '\0';
	}

	char * ret = elektraFormat (format, first, second);
	elektraFree (format);
	return ret;
}
Exemple #18
0
static void appendToKey (Key * key, const char * line)
{
	char * buffer;
	size_t len = keyGetValueSize (key) + elektraStrLen (line) - 1;
	buffer = elektraMalloc (len);
	snprintf (buffer, len, "%s%s", keyString (key), line);
	keySetString (key, buffer);
	elektraFree (buffer);
}
Exemple #19
0
/**
 * Generate a C-Style key and stream it.
 *
 * This keyset can be used to include as c-code for
 * applikations using elektra.
 *
 * @param key the key object to work with
 * @param stream the file pointer where to send the stream
 * @param options KDB_O_SHOWINDICES, KDB_O_IGNORE_COMMENT, KDB_O_SHOWINFO
 * @retval 1 on success
 * @ingroup stream
 */
int keyGenerate (const Key * key, FILE * stream, option_t options)
{
	size_t n = keyGetNameSize (key);
	if (n > 1)
	{
		char * nam = (char *) elektraMalloc (n);
		if (nam == NULL) return -1;
		keyGetName (key, nam, n);
		fprintf (stream, "\tkeyNew (\"%s\"", nam);
		elektraFree (nam);
	}

	size_t s = keyGetValueSize (key);
	if (s > 1)
	{
		char * str = (char *) elektraMalloc (s);
		if (str == NULL) return -1;
		if (keyIsBinary (key))
		{
			keyGetBinary (key, str, s);
			fprintf (stream, ", KEY_SIZE, \"%zd\"", keyGetValueSize (key));
		}
		else
		{
			keyGetString (key, str, s);
		}
		fprintf (stream, ", KEY_VALUE, \"%s\"", str);
		elektraFree (str);
	}

	const Key * meta;
	Key * dup = keyDup (key);
	keyRewindMeta (dup);
	while ((meta = keyNextMeta (dup)))
	{
		fprintf (stream, ", KEY_META, \"%s\", \"%s\"", keyName (meta), keyString (meta));
	}
	keyDel (dup);

	fprintf (stream, ", KEY_END)");

	if (options == 0) return 1; /* dummy to make icc happy */
	return 1;
}
Exemple #20
0
/**
 * @internal
 *
 * Compare 2 keys.
 *
 * The returned flags bit array has 1s (differ) or 0s (equal) for each key
 * meta info compared, that can be logically ORed using @c #keyswitch_t flags.
 * @link keyswitch_t::KEY_NAME KEY_NAME @endlink,
 * @link keyswitch_t::KEY_VALUE KEY_VALUE @endlink,
 * @link keyswitch_t::KEY_OWNER KEY_OWNER @endlink,
 * @link keyswitch_t::KEY_COMMENT KEY_COMMENT @endlink,
 * @link keyswitch_t::KEY_META KEY_META @endlink (will be set in addition to owner and comment),
 *
 * @par A very simple example would be
 * @code
 Key *key1, *key;
 uint32_t changes;

// omited key1 and key2 initialization and manipulation

changes=keyCompare(key1,key2);

if (changes == 0) printf("key1 and key2 are identicall\n");

if (changes & KEY_VALUE)
printf("key1 and key2 have different values\n");

if (changes & KEY_UID)
printf("key1 and key2 have different UID\n");

 *
 * @endcode
 *
 *
 * @par Example of very powerful specific Key lookup in a KeySet:
 * @code
 Key *base = keyNew ("/sw/MyApp/something", KEY_END);
 KDB *handle = kdbOpen(base);
 KeySet *ks=ksNew(0, KS_END);
 Key *current;
 uint32_t match;
 uint32_t interests;


 kdbGet(handle, ks, base);

// we are interested only in key type and access permissions
interests=(KEY_TYPE | KEY_MODE);

ksRewind(ks);	// put cursor in the beginning
while ((curren=ksNext(ks))) {
match=keyCompare(current,base);

if ((~match & interests) == interests)
printf("Key %s has same type and permissions of base key",keyName(current));

// continue walking in the KeySet....
}

// now we want same name and/or value
interests=(KEY_NAME | KEY_VALUE);

// we don't really need ksRewind(), since previous loop achieved end of KeySet
ksRewind(ks);
while ((current=ksNext(ks))) {
match=keyCompare(current,base);

if ((~match & interests) == interests) {
printf("Key %s has same name, value, and sync status
of base key",keyName(current));
}
// continue walking in the KeySet....
}

ksDel(ks);
kdbClose (handle, base);
keyDel(base);
* @endcode
*
* @return a bit array pointing the differences
* @param key1 first key
* @param key2 second key
* @see #keyswitch_t
* @ingroup keytest
	*/
keyswitch_t keyCompare (const Key * key1, const Key * key2)
{
	if (!key1 && !key2) return 0;
	if (!key1 || !key2) return KEY_NULL;

	keyswitch_t ret = 0;
	ssize_t nsize1 = keyGetNameSize (key1);
	ssize_t nsize2 = keyGetNameSize (key2);
	const char * name1 = keyName (key1);
	const char * name2 = keyName (key2);
	const Key * comment1 = keyGetMeta (key1, "comment");
	const Key * comment2 = keyGetMeta (key2, "comment");
	const char * owner1 = keyOwner (key1);
	const char * owner2 = keyOwner (key2);
	const void * value1 = keyValue (key1);
	const void * value2 = keyValue (key2);
	ssize_t size1 = keyGetValueSize (key1);
	ssize_t size2 = keyGetValueSize (key2);

	// TODO: might be (binary) by chance
	if (strcmp (keyString (comment1), keyString (comment2))) ret |= KEY_COMMENT;

	if (strcmp (owner1, owner2)) ret |= KEY_OWNER;

	if (keyCompareMeta (key1, key2)) ret |= KEY_META;

	if (nsize1 != nsize2)
		ret |= KEY_NAME;
	else if (!name1 || !name2)
		ret |= KEY_NAME;
	else if (strcmp (name1, name2))
		ret |= KEY_NAME;


	if (size1 != size2)
		ret |= KEY_VALUE;
	else if (!value1 || !value2)
		ret |= KEY_VALUE;
	else if (memcmp (value1, value2, size1))
		ret |= KEY_VALUE;

	// TODO: rewind metadata to previous position
	return ret;
}
Exemple #21
0
/**
 * Generate a C-Style key and stream it.
 *
 * This keyset can be used to include as c-code for
 * applikations using elektra.
 *
 * @param key the key object to work with
 * @param stream the file pointer where to send the stream
 * @param options KDB_O_SHOWINDICES, KDB_O_IGNORE_COMMENT, KDB_O_SHOWINFO
 * @retval 1 on success
 * @ingroup stream
 */
int keyGenerate(const Key * key, FILE *stream, option_t options)
{
	size_t s;
	char * str;

	size_t c;
	char * com;

	size_t n;
	char * nam;

	n = keyGetNameSize (key);
	if (n>1)
	{
		nam = (char*) elektraMalloc (n);
		if (nam == NULL) return -1;
		keyGetName (key, nam, n);
		fprintf(stream,"\tkeyNew (\"%s\"", nam);
		elektraFree (nam);
	}

	s = keyGetValueSize (key);
	if (s>1)
	{
		str = (char*) elektraMalloc (s);
		if (str == NULL) return -1;
		if (keyIsBinary(key)) keyGetBinary(key, str, s);
		else keyGetString (key, str, s);
		fprintf(stream,", KEY_VALUE, \"%s\"", str);
		elektraFree (str);
	}

	c = keyGetCommentSize (key);
	if (c>1)
	{
		com = (char*) elektraMalloc (c);
		if (com == NULL) return -1;
		keyGetComment (key, com, c);
		fprintf(stream,", KEY_COMMENT, \"%s\"", com);
		elektraFree (com);
	}

	if (! (keyGetMode(key) == 0664 || (keyGetMode(key) == 0775)))
	{
		fprintf(stream,", KEY_MODE, 0%3o", keyGetMode(key));
	}

	fprintf(stream,", KEY_END)");

	if (options == 0) return 1; /* dummy to make icc happy */
	return 1;
}
Exemple #22
0
/**
 * Get key full name, including the user domain name.
 *
 * @return number of bytes written
 * @retval 1 on empty name
 * @retval -1 on NULL pointers
 * @retval -1 if maxSize is 0 or larger than SSIZE_MAX
 * @param key the key object
 * @param returnedName pre-allocated memory to write the key name
 * @param maxSize maximum number of bytes that will fit in returnedName, including the final NULL
 * @ingroup keyname
 */
ssize_t keyGetFullName (const Key * key, char * returnedName, size_t maxSize)
{
	size_t userSize = sizeof ("user") - 1;
	size_t ownerSize;
	ssize_t length;
	ssize_t maxSSize;
	char * cursor;

	if (!key) return -1;
	if (!returnedName) return -1;
	if (!maxSize) return -1;

	if (maxSize > SSIZE_MAX) return -1;
	maxSSize = maxSize;

	length = keyGetFullNameSize (key);
	if (length == 1)
	{
		/*errno=KDB_ERR_NOKEY;*/
		returnedName[0] = 0;
		return length;
	}
	else if (length < 0)
		return length;
	else if (length > maxSSize)
	{
		/* errno=KDB_ERR_TRUNC; */
		return -1;
	}

	cursor = returnedName;
	if (keyIsUser (key))
	{
		strncpy (cursor, key->key, userSize);
		cursor += userSize;
		if (keyGetMeta (key, "owner"))
		{
			*cursor = ':';
			++cursor;
			ownerSize = keyGetValueSize (keyGetMeta (key, "owner")) - 1;
			strncpy (cursor, keyValue (keyGetMeta (key, "owner")), ownerSize);
			cursor += ownerSize;
		}
		strcpy (cursor, key->key + userSize);
	}
	else
		strcpy (cursor, key->key);

	return length;
}
Exemple #23
0
int main ()
{
	Key * k;
	Key * c;
	const Key * meta;
	k = keyNew ("user/metakey", KEY_END);
	c = keyNew ("user/metacopy", KEY_END);

	keySetMeta (k, "hello", "hello_world");

	keySetMeta (k, "mode", "0644");
	keySetMeta (k, "time", "1271234264");
	keySetMeta (k, "empty", "");

	meta = keyGetMeta (k, "hello");
	printf ("Metadata %s has the value %s with the value size %zd\n", keyName (meta), (const char *)keyValue (meta),
		keyGetValueSize (meta));
	printf ("Metadata mode has the value %s\n", (const char *)keyValue (keyGetMeta (k, "mode")));
	printf ("Metadata time has the value %s\n", (const char *)keyValue (keyGetMeta (k, "time")));
	printf ("Metadata empty has the value %s\n", (const char *)keyValue (keyGetMeta (k, "empty")));

	if (!keyGetMeta (k, "nonexist")) printf ("Check if a metadata exist\n");

	keySetMeta (k, "hello", "between");
	keyCopyMeta (c, k, "hello");

	if (keyGetMeta (k, "hello") == keyGetMeta (c, "hello")) printf ("Check if they point to the same metadata after a copy\n");

	printf ("Metadata hello now has the value %s\n", (const char *)keyValue (keyGetMeta (k, "hello")));

	keySetMeta (k, "hello", 0);

	printf ("Metadata hello now has the value %s (after dropping)\n", (const char *)keyValue (keyGetMeta (k, "hello")));

	keySetMeta (k, "hello", "goodbye");

	printf ("Metadata hello now has the value %s\n", (const char *)keyValue (keyGetMeta (k, "hello")));

	printf ("Now we will output all metadata of the key:\n");
	keyRewindMeta (k);
	while ((meta = keyNextMeta (k)) != 0)
	{
		printf ("%s=%s\n", keyName (meta), (const char *)keyValue (meta));
	}

	keyDel (k);

	return 0;
}
static void test_keySetBinary (const size_t storagePlugin, const char * tmpFile)
{
	Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
	open_storage_plugin (storagePlugin);
	Plugin * plugin = plugins[storagePlugin];

	KeySet * ks = metaTestKeySet ();
	const char * name = "user/tests/storage/specialkey";
	size_t realValueSize = 42;
	void * value = elektraMalloc (realValueSize);
	memset (value, 42, realValueSize);

	Key * key = keyNew (name, KEY_END);
	keySetBinary (key, value, realValueSize);
	ksAppendKey (ks, key);
	succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
	succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");

	Key * found = ksLookupByName (ks, name, KDB_O_POP);
	succeed_if (found, "did not find key");

	// now set a new key value to the Key _after_ kdbGet
	size_t newValueSize = 4096;
	void * newValue = elektraMalloc (newValueSize);
	memset (newValue, 253, newValueSize);

	succeed_if (keySetBinary (found, newValue, newValueSize) == (ssize_t) newValueSize, "Key binary could not be set");

	ksAppendKey (ks, found);
	succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
	succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");

	found = ksLookupByName (ks, name, 0);
	succeed_if (found, "did not find key");

	ssize_t apiValueSize = keyGetValueSize (found);
	char * apiValue = elektraMalloc (apiValueSize);
	succeed_if (keyGetBinary (found, apiValue, apiValueSize) == (ssize_t) newValueSize, "Key binary has wrong size");

	succeed_if (elektraStrNCmp (value, apiValue, realValueSize) != 0, "Key binary value is wrong");
	succeed_if (elektraStrNCmp (newValue, apiValue, newValueSize) == 0, "Key binary value is wrong");

	elektraFree (newValue);
	elektraFree (apiValue);
	elektraFree (value);
	keyDel (parentKey);
	ksDel (ks);
	closeStoragePlugin (storagePlugin);
}
Exemple #25
0
/*
 * Appends a line to the MetaKey of the supplied Key
 * If no MetaKey with the given name exists yet, a new
 * one is created containing the supplied line. If
 * the MetaKey exists, the supplied line is added as
 * a new line to the value of the MetaKey (i.e. a newline
 * followed by the given line is appended to the metadata)
 *
 * @param	target the Key whose MetaKey is to be modified
 * @param	metaName the name of the MetaKey which is to be modified
 * @param	line the line to be appended to the matadata
 * @return	the new value size of the modified MetaKey
 * @retval 	-1 on NULL pointers or if a memory allocation error occurs
 *
 * @see keyGetValueSize(Key *key)
 *
 */
int elektraKeyAppendMetaLine (Key * target, const char * metaName, const char * line)
{
    if (!target) return 0;
    if (!metaName) return 0;
    if (!line) return 0;

    if (!keyGetMeta (target, metaName))
    {
        keySetMeta (target, metaName, line);
        return keyGetValueSize (keyGetMeta (target, metaName));
    }

    const Key * existingMeta = keyGetMeta (target, metaName);
    char * buffer = elektraMalloc (keyGetValueSize (existingMeta) + strlen (line) + 1);
    if (!buffer) return 0;

    keyGetString (existingMeta, buffer, keyGetValueSize (existingMeta));
    strcat (buffer, "\n");
    strncat (buffer, line, strlen (line));

    keySetMeta (target, metaName, buffer);
    elektraFree (buffer);
    return keyGetValueSize (keyGetMeta (target, metaName));
}
Exemple #26
0
void j (Key *k)
{
	size_t size = keyGetValueSize (k);
	char *value = malloc (size);
	int bstring = keyIsString (k);

	// receive key g_c
	memcpy (value, keyValue(k), size);
	keyCopy (k, g_c);
	if (bstring) keySetString (k, value);
	else keySetBinary (k, value, size);
	free (value);
	// the caller will see the changed key k
	// with the metadata from g_c
}
Exemple #27
0
/**
 * Calculates number of bytes needed to store a key comment, including
 * final NULL.
 *
 * Use this method to know to size for allocated memory to retrieve
 * a key comment.
 *
 * See keySetComment() for more information on comments.
 *
 * For an empty key name you need one byte to store the ending NULL.
 * For that reason 1 is returned.
 *
 * @code
 char *buffer;
 buffer = elektraMalloc (keyGetCommentSize (key));
// use this buffer to store the comment
// pass keyGetCommentSize (key) for maxSize
 * @endcode
 *
 * @param key the key object to work with
 * @return number of bytes needed
 * @retval 1 if there is no comment
 * @retval -1 on NULL pointer
 * @see keyGetComment(), keySetComment()
 */
ssize_t keyGetCommentSize (const Key * key)
{
	ssize_t size;
	if (!key) return -1;

	size = keyGetValueSize (keyGetMeta (key, "comment"));

	if (!size || size == -1)
	{
		/*errno=KDB_ERR_NODESC;*/
		return 1;
	}

	return size;
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForEncryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	kdb_octet_t salt[ELEKTRA_CRYPTO_DEFAULT_SALT_LEN] = { 0 };
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE] = { 0 };
	char * saltHexString = NULL;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// generate the salt
	pthread_mutex_lock (&mutex_ssl);
	if (!RAND_bytes (salt, ELEKTRA_CRYPTO_DEFAULT_SALT_LEN - 1))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey, "failed to generate random salt with error code %lu",
				    ERR_get_error ());
		pthread_mutex_unlock (&mutex_ssl);
		return -1;
	}
	pthread_mutex_unlock (&mutex_ssl);
	saltHexString = ELEKTRA_PLUGIN_FUNCTION (ELEKTRA_PLUGIN_NAME_C, base64Encode) (salt, sizeof (salt));
	if (!saltHexString)
	{
		ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed");
		return -1;
	}
	keySetMeta (k, ELEKTRA_CRYPTO_META_SALT, saltHexString);
	elektraFree (saltHexString);

	// read iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// generate/derive the cryptographic key and the IV
	pthread_mutex_lock (&mutex_ssl);
	if (!PKCS5_PBKDF2_HMAC_SHA1 (keyValue (masterKey), keyGetValueSize (masterKey), salt, sizeof (salt), iterations, KEY_BUFFER_SIZE,
				     keyBuffer))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to create a cryptographic key for encryption. Libcrypto returned error code: %lu",
				    ERR_get_error ());
		pthread_mutex_unlock (&mutex_ssl);
		return -1;
	}
	pthread_mutex_unlock (&mutex_ssl);

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_SSL_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_SSL_KEYSIZE, ELEKTRA_CRYPTO_SSL_BLOCKSIZE);
	return 1;
}
Exemple #29
0
int elektraHexcodeGet (Plugin * handle, KeySet * returned, Key * parentKey)
{
	/* get all keys */

	if (!strcmp (keyName (parentKey), "system/elektra/modules/hexcode"))
	{
		KeySet * pluginConfig =
			ksNew (30, keyNew ("system/elektra/modules/hexcode", KEY_VALUE, "hexcode plugin waits for your orders", KEY_END),
			       keyNew ("system/elektra/modules/hexcode/exports", KEY_END),
			       keyNew ("system/elektra/modules/hexcode/exports/get", KEY_FUNC, elektraHexcodeGet, KEY_END),
			       keyNew ("system/elektra/modules/hexcode/exports/set", KEY_FUNC, elektraHexcodeSet, KEY_END),
			       keyNew ("system/elektra/modules/hexcode/exports/open", KEY_FUNC, elektraHexcodeOpen, KEY_END),
			       keyNew ("system/elektra/modules/hexcode/exports/close", KEY_FUNC, elektraHexcodeClose, KEY_END),
#include "readme_hexcode.c"
			       keyNew ("system/elektra/modules/hexcode/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
		ksAppend (returned, pluginConfig);
		ksDel (pluginConfig);
		return 1;
	}

	CHexData * hd = elektraPluginGetData (handle);
	if (!hd->buf)
	{
		hd->buf = elektraMalloc (1000);
		hd->bufalloc = 1000;
	}

	Key * cur;
	ksRewind (returned);
	while ((cur = ksNext (returned)) != 0)
	{
		size_t valsize = keyGetValueSize (cur);
		if (valsize > hd->bufalloc)
		{
			hd->bufalloc = valsize;
			hd->buf = realloc (hd->buf, hd->bufalloc);
		}

		elektraHexcodeDecode (cur, hd);
	}

	return 1; /* success */
}
/**
 * @brief derive the cryptographic key and IV for a given (Elektra) Key k
 * @param config KeySet holding the plugin/backend configuration
 * @param errorKey holds an error description in case of failure
 * @param masterKey holds the decrypted master password from the plugin configuration
 * @param k the (Elektra)-Key to be encrypted
 * @param cKey (Elektra)-Key holding the cryptographic material
 * @param cIv (Elektra)-Key holding the initialization vector
 * @retval -1 on failure. errorKey holds the error description.
 * @retval 1 on success
 */
static int getKeyIvForEncryption (KeySet * config, Key * errorKey, Key * masterKey, Key * k, Key * cKey, Key * cIv)
{
	gcry_error_t gcry_err;
	kdb_octet_t salt[ELEKTRA_CRYPTO_DEFAULT_SALT_LEN];
	kdb_octet_t keyBuffer[KEY_BUFFER_SIZE];
	char * saltHexString = NULL;

	ELEKTRA_ASSERT (masterKey != NULL, "Parameter `masterKey` must not be NULL");

	// generate the salt
	gcry_create_nonce (salt, sizeof (salt));
	const int encodingResult = CRYPTO_PLUGIN_FUNCTION (base64Encode) (errorKey, salt, sizeof (salt), &saltHexString);
	if (encodingResult < 0)
	{
		// error in libinvoke - errorKey has been set by base64Encode
		return -1;
	}
	if (!saltHexString)
	{
		ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed");
		return -1;
	}
	keySetMeta (k, ELEKTRA_CRYPTO_META_SALT, saltHexString);
	elektraFree (saltHexString);

	// read iteration count
	const kdb_unsigned_long_t iterations = CRYPTO_PLUGIN_FUNCTION (getIterationCount) (errorKey, config);

	// generate/derive the cryptographic key and the IV
	if ((gcry_err = gcry_kdf_derive (keyValue (masterKey), keyGetValueSize (masterKey), GCRY_KDF_PBKDF2, GCRY_MD_SHA512, salt,
					 sizeof (salt), iterations, KEY_BUFFER_SIZE, keyBuffer)))
	{
		ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_INTERNAL_ERROR, errorKey,
				    "Failed to create a cryptographic key for encryption because: %s", gcry_strerror (gcry_err));
		return -1;
	}

	keySetBinary (cKey, keyBuffer, ELEKTRA_CRYPTO_GCRY_KEYSIZE);
	keySetBinary (cIv, keyBuffer + ELEKTRA_CRYPTO_GCRY_KEYSIZE, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE);
	return 1;
}