/** * @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; }
/** * @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; }
/** * @brief create new KeySet and add a working configuration to it. */ static void getWorkingConfiguration(KeySet **ks) { Key *configKey = keyNew("proc/elektra/modules/crypto/key-derivation/key", KEY_END); keySetBinary(configKey, key, sizeof(key)); Key *configIv = keyNew("proc/elektra/modules/crypto/key-derivation/iv", KEY_END); keySetBinary(configIv, iv, sizeof(iv)); (*ks) = ksNew(2, configKey, configIv, KS_END); }
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); }
/** * @brief create new KeySet and add an invalid configuration to it. * * The key in ks has an invalid size. */ static void getInvalidConfiguration(KeySet **ks) { const unsigned char wrongKey[] = { 0x01, 0x02, 0x03 }; Key *configKey = keyNew("proc/elektra/modules/crypto/key-derivation/key", KEY_END); keySetBinary(configKey, wrongKey, sizeof(wrongKey)); Key *configIv = keyNew("proc/elektra/modules/crypto/key-derivation/iv", KEY_END); keySetBinary(configIv, iv, sizeof(iv)); (*ks) = ksNew(2, configKey, configIv, KS_END); }
static KeySet * pwentToKS (struct passwd * pwd, Key * parentKey, SortBy index) { KeySet * ks = ksNew (0, KS_END); Key * append = keyNew (keyName (parentKey), KEY_END); char id[ID_MAX_CHARACTERS]; if (index == UID) { snprintf (id, sizeof (id), "%u", pwd->pw_uid); keyAddBaseName (append, id); keySetBinary (append, 0, 0); ksAppendKey (ks, keyDup (append)); keyAddBaseName (append, "name"); keySetString (append, pwd->pw_name); } else { keyAddBaseName (append, pwd->pw_name); keySetBinary (append, 0, 0); ksAppendKey (ks, keyDup (append)); snprintf (id, sizeof (id), "%u", pwd->pw_uid); keyAddBaseName (append, "uid"); keySetString (append, id); } ksAppendKey (ks, keyDup (append)); keySetString (append, 0); keySetBaseName (append, "shell"); keySetString (append, pwd->pw_shell); ksAppendKey (ks, keyDup (append)); keySetString (append, 0); keySetBaseName (append, "home"); keySetString (append, pwd->pw_dir); ksAppendKey (ks, keyDup (append)); keySetString (append, 0); keySetBaseName (append, "gid"); snprintf (id, sizeof (id), "%u", pwd->pw_gid); keySetString (append, id); ksAppendKey (ks, keyDup (append)); keySetString (append, 0); keySetBaseName (append, "passwd"); keySetString (append, pwd->pw_passwd); ksAppendKey (ks, keyDup (append)); keySetString (append, 0); keySetBaseName (append, "gecos"); keySetString (append, pwd->pw_gecos); ksAppendKey (ks, keyDup (append)); keyDel (append); return ks; }
static int iniSectionToElektraKey (void *vhandle, const char *section) { CallbackHandle *handle = (CallbackHandle *)vhandle; Key *appendKey = keyDup (handle->parentKey); keySetMeta(appendKey, "ini/lastSection", 0); createUnescapedKey(appendKey, section); Key *existingKey = NULL; if ((existingKey = ksLookup(handle->result, appendKey, KDB_O_NONE))) { keyDel(appendKey); if(!handle->mergeSections) { ELEKTRA_SET_ERRORF(140, handle->parentKey, "Section name: %s\n", section); return 0; } keySetMeta(existingKey, "ini/duplicate", ""); return 1; } setSectionNumber(handle->parentKey, appendKey, handle->result); setOrderNumber(handle->parentKey, appendKey); keySetBinary(appendKey, 0, 0); flushCollectedComment (handle, appendKey); ksAppendKey(handle->result, appendKey); return 1; }
static void test_keyValue (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 valueSize = 42; void * value = elektraMalloc (valueSize); memset (value, 42, valueSize); Key * key = keyNew (name, KEY_END); keySetBinary (key, value, valueSize); ksAppendKey (ks, keyDup (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"); compare_key (key, found); elektraFree (value); keyDel (parentKey); ksDel (ks); keyDel (key); closeStoragePlugin (storagePlugin); }
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(); }
/** * @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; }
/** * @brief create new KeySet and add an incomplete configuration to it. * * The required key "/elektra/modules/crypto/key-derivation/iv" is missing. */ static void getIncompleteConfiguration(KeySet **ks) { Key *configKey = keyNew("proc/elektra/modules/crypto/key-derivation/key", KEY_END); keySetBinary(configKey, key, sizeof(key)); (*ks) = ksNew(1, configKey, KS_END); }
KeySet *getNullKeys(void) { Key *k1, *k2; KeySet *ks = ksNew(10, k1 = keyNew("user/tests/yajl/nullkey", KEY_VALUE, "will be removed", KEY_END), k2 = keyNew("user/tests/yajl/second_nullkey", KEY_VALUE, "will be removed too", KEY_END), KS_END ); keySetBinary(k1, NULL, 0); keySetBinary(k2, NULL, 0); ksRewind(ks); // shouldn't that be default? return ks; }
/** * @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; }
void test_type() { Key *key; succeed_if (key = keyNew(0), "could not create a new key"); succeed_if (keyValue(keyGetMeta(key, "binary")) == 0, "wrong type after key creation"); succeed_if (keySetString (key, "mystring") == sizeof("mystring"), "could not set string"); succeed_if (keyValue(keyGetMeta(key, "binary")) == 0, "wrong type after setting string"); succeed_if (keySetBinary (key, "mystring", sizeof("mystring")) == sizeof("mystring"), "could not set binary"); succeed_if (keyValue(keyGetMeta(key, "binary")) != 0, "wrong type after setting string"); keyDel (key); }
/** * @internal * Add plugin at placement to list plugin configuration and apply it. * * @param list List plugin * @param plugin Plugin to add * @param placement Placement name * @retval 0 on error * @retval 0 on success */ static int listAddPlugin (Plugin * list, Plugin * plugin, char * placement) { ELEKTRA_NOT_NULL (list); ELEKTRA_NOT_NULL (plugin); ELEKTRA_NOT_NULL (placement); KeySet * newConfig = ksDup (list->config); // Find name for next item in plugins array Key * configBase = keyNew ("user/plugins", KEY_END); KeySet * array = elektraArrayGet (configBase, newConfig); Key * pluginItem = elektraArrayGetNextKey (array); ELEKTRA_NOT_NULL (pluginItem); keySetString (pluginItem, plugin->name); keyDel (configBase); // Create key with plugin handle Key * pluginHandle = keyDup (pluginItem); keyAddName (pluginHandle, "handle"); keySetBinary (pluginHandle, &plugin, sizeof (plugin)); // Create key with plugin placement char * placementType = placementToListPositionType (placement); if (placementType == NULL) { keyDel (configBase); keyDel (pluginItem); keyDel (pluginHandle); return 0; } Key * pluginPlacements = keyDup (pluginItem); keyAddName (pluginPlacements, "placements/"); keyAddName (pluginPlacements, placementType); keySetString (pluginPlacements, placement); // Append keys to list plugin configuration ksAppendKey (newConfig, pluginItem); ksAppendKey (newConfig, pluginHandle); ksAppendKey (newConfig, pluginPlacements); ksDel (array); ksDel (list->config); // Apply new configuration list->config = newConfig; list->kdbOpen (list, NULL); return 1; }
static int elektraYajlParseNull (void * ctx) { KeySet * ks = (KeySet *)ctx; elektraYajlIncrementArrayEntry (ks); Key * current = ksCurrent (ks); keySetBinary (current, NULL, 0); #ifdef ELEKTRA_YAJL_VERBOSE printf ("elektraYajlParseNull\n"); #endif return 1; }
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 }
static void test_gpg (void) { // Plugin configuration KeySet * conf = newPluginConfiguration (); Key * errorKey = keyNew (0); // install the gpg key char * argv[] = { "", "-a", "--import", NULL }; const size_t argc = 4; Key * msg = keyNew (0); keySetBinary (msg, test_key_asc, test_key_asc_len); succeed_if (CRYPTO_PLUGIN_FUNCTION (gpgCall) (conf, errorKey, msg, argv, argc) == 1, "failed to install the GPG test key"); keyDel (msg); keyDel (errorKey); ksDel (conf); }
void test_ro() { Key *key; key = keyNew(KEY_END); key->flags |= KEY_FLAG_RO; succeed_if (keySetString(key, "a") == -1, "read only string, not allowed to set"); succeed_if (keySetBinary(key, "a", 2) == -1, "read only string, not allowed to set"); succeed_if (keySetName(key, "user") == -1, "read only string, not allowed to set"); succeed_if (keySetMeta(key, "meta", "value") == -1, "read only string, not allowed to set"); keyDel (key); key = keyNew(KEY_END); succeed_if (keySetMeta(key, "meta", "value") == sizeof("value"), "could not set meta"); // TODO check if RO keyDel (key); }
static void test_enc_and_dec_with_binary() { elektraCryptoHandle *handle; KeySet *config; Key *errorKey = keyNew(KEY_END); const unsigned char original[] = { 0x00, 0x01, 0x02, 0x03 }; unsigned char content[64]; unsigned long read = 0; Key *k = keyNew("user/plugins/crypto/gcrypt/test-enc-dec-bin", KEY_END); keySetBinary(k, original, sizeof(original)); 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( keyIsBinary(k) == 1, "key is of non-binary type"); read = keyGetBinary(k, content, sizeof(content)); succeed_if( read == sizeof(original), "decrypted value is of different length than original" ); if(read == sizeof(original)) { succeed_if( memcmp(original, content, read) == 0, "decrypted value differs from original"); } keyDel(k); keyDel(errorKey); ksDel(config); elektraCryptoTeardown(); }
int elektraCryptoGcryDecrypt (elektraCryptoHandle * handle, Key * k, Key * errorKey) { kdb_octet_t * value = (kdb_octet_t *)keyValue (k); const size_t valueLen = keyGetValueSize (k); kdb_octet_t * output; kdb_octet_t cipherBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE]; kdb_octet_t contentBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE]; kdb_unsigned_long_t written = 0; gcry_error_t gcry_err; // initialize crypto header data kdb_unsigned_long_t contentLen = 0; kdb_octet_t flags = ELEKTRA_CRYPTO_FLAG_NONE; // check if key has been encrypted in the first place const Key * metaEncrypted = keyGetMeta (k, ELEKTRA_CRYPTO_META_ENCRYPT); if (metaEncrypted == NULL || strlen (keyValue (metaEncrypted)) == 0) { // nothing to do return 1; } // plausibility check if (valueLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE != 0) { ELEKTRA_SET_ERROR (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "value length is not a multiple of the block size"); return (-1); } // prepare buffer for plain text output output = elektraMalloc (valueLen); if (output == NULL) { ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed"); return (-1); } // decrypt the header (1st block) memcpy (cipherBuffer, value, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); gcry_err = gcry_cipher_decrypt (*handle, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "Decryption failed because: %s", gcry_strerror (gcry_err)); elektraFree (output); return (-1); } // restore the header data memcpy (&flags, contentBuffer, sizeof (flags)); memcpy (&contentLen, contentBuffer + sizeof (flags), sizeof (contentLen)); // decrypt content block by block // (i = start of the current block and the 1st block has already been consumed) for (kdb_unsigned_long_t i = ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; i < valueLen; i += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) { memcpy (cipherBuffer, (value + i), ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); gcry_err = gcry_cipher_decrypt (*handle, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "Decryption failed because: %s", gcry_strerror (gcry_err)); elektraFree (output); return (-1); } memcpy ((output + i - ELEKTRA_CRYPTO_GCRY_BLOCKSIZE), contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); written += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; } if (written < contentLen) { ELEKTRA_SET_ERROR (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "Content was shorter than described in the header"); elektraFree (output); return (-1); } // write back the cipher text to the key if ((flags & ELEKTRA_CRYPTO_FLAG_STRING) == ELEKTRA_CRYPTO_FLAG_STRING) { keySetString (k, (const char *)output); } else if ((flags & ELEKTRA_CRYPTO_FLAG_NULL) == ELEKTRA_CRYPTO_FLAG_NULL || contentLen == 0) { keySetBinary (k, NULL, 0); } else { keySetBinary (k, output, contentLen); } elektraFree (output); return 1; }
int elektraCryptoGcryEncrypt (elektraCryptoHandle * handle, Key * k, Key * errorKey) { const kdb_octet_t * value = (kdb_octet_t *)keyValue (k); size_t outputLen; gcry_error_t gcry_err; kdb_octet_t * output; kdb_octet_t cipherBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE]; kdb_octet_t contentBuffer[ELEKTRA_CRYPTO_GCRY_BLOCKSIZE] = { 0 }; // check if key has been marked for encryption const Key * metaEncrypt = keyGetMeta (k, ELEKTRA_CRYPTO_META_ENCRYPT); if (metaEncrypt == NULL || strlen (keyValue (metaEncrypt)) == 0) { // nothing to do return 1; } // prepare the crypto header data const kdb_unsigned_long_t contentLen = keyGetValueSize (k); kdb_octet_t flags; switch (keyIsString (k)) { case 1: // string flags = ELEKTRA_CRYPTO_FLAG_STRING; break; case -1: // NULL pointer flags = ELEKTRA_CRYPTO_FLAG_NULL; break; default: // binary flags = ELEKTRA_CRYPTO_FLAG_NONE; break; } // prepare buffer for cipher text output // NOTE the header goes into the first block if (contentLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE == 0) { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 1; } else { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 2; } outputLen *= ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; output = elektraMalloc (outputLen); if (output == NULL) { ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed"); return (-1); } // encrypt the header (1st block) memcpy (contentBuffer, &flags, sizeof (flags)); memcpy (contentBuffer + sizeof (flags), &contentLen, sizeof (contentLen)); gcry_err = gcry_cipher_encrypt (*handle, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_ENCRYPT_FAIL, errorKey, "Encryption failed because: %s", gcry_strerror (gcry_err)); elektraFree (output); return (-1); } memcpy (output, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); // encrypt content block by block (i = start of the current block) for (kdb_unsigned_long_t i = 0; i < contentLen; i += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) { // load content partition into the content buffer kdb_unsigned_long_t partitionLen = ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; if ((i + 1) * ELEKTRA_CRYPTO_GCRY_BLOCKSIZE > contentLen) { partitionLen = contentLen - (i * ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); } memcpy (contentBuffer, (value + i), partitionLen); gcry_err = gcry_cipher_encrypt (*handle, cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, contentBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_ENCRYPT_FAIL, errorKey, "Encryption failed because: %s", gcry_strerror (gcry_err)); elektraFree (output); return (-1); } memcpy ((output + i + ELEKTRA_CRYPTO_GCRY_BLOCKSIZE), cipherBuffer, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE); } // write back the cipher text to the key keySetBinary (k, output, outputLen); elektraFree (output); return 1; }
int elektraCryptoGcryDecrypt (elektraCryptoHandle * handle, Key * k, Key * errorKey) { gcry_error_t gcry_err; // parse salt length from crypto payload kdb_unsigned_long_t saltLen = 0; if (CRYPTO_PLUGIN_FUNCTION (getSaltFromPayload) (errorKey, k, NULL, &saltLen) != 1) { return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromPayload)() } saltLen += sizeof (kdb_unsigned_long_t); // set payload pointer const kdb_octet_t * payload = ((kdb_octet_t *) keyValue (k)) + saltLen + ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; const size_t payloadLen = keyGetValueSize (k) - saltLen - ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; // plausibility check if (payloadLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE != 0) { ELEKTRA_SET_ERROR (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "value length is not a multiple of the block size"); return -1; } // prepare buffer for plain text output and crypto operations kdb_octet_t * output = elektraMalloc (payloadLen); if (!output) { ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed"); return -1; } // initialize crypto header data kdb_unsigned_long_t contentLen = 0; kdb_octet_t flags = ELEKTRA_CRYPTO_FLAG_NONE; // in-place decryption memcpy (output, payload, payloadLen); gcry_err = gcry_cipher_decrypt (*handle, output, payloadLen, NULL, 0); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "Decryption failed because: %s", gcry_strerror (gcry_err)); memset (output, 0, payloadLen); elektraFree (output); return -1; } // restore the header data memcpy (&flags, output, sizeof (flags)); memcpy (&contentLen, output + sizeof (flags), sizeof (contentLen)); const kdb_octet_t * data = output + ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; const size_t dataLen = payloadLen - ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; // validate restored content length if (contentLen > dataLen) { ELEKTRA_SET_ERROR ( ELEKTRA_ERROR_CRYPTO_DECRYPT_FAIL, errorKey, "restored content length is bigger than the available amount of decrypted data. The header is possibly corrupted."); memset (output, 0, payloadLen); elektraFree (output); return -1; } // restore the key to its original status if ((flags & ELEKTRA_CRYPTO_FLAG_STRING) == ELEKTRA_CRYPTO_FLAG_STRING && contentLen > 0) { keySetString (k, (const char *) data); } else if ((flags & ELEKTRA_CRYPTO_FLAG_NULL) == ELEKTRA_CRYPTO_FLAG_NULL || contentLen == 0) { keySetBinary (k, NULL, 0); } else { keySetBinary (k, data, contentLen); } memset (output, 0, payloadLen); elektraFree (output); return 1; }
int elektraCryptoGcryEncrypt (elektraCryptoHandle * handle, Key * k, Key * errorKey) { size_t outputLen; gcry_error_t gcry_err; // prepare the salt for payload output kdb_unsigned_long_t saltLen = 0; kdb_octet_t * salt = NULL; if (CRYPTO_PLUGIN_FUNCTION (getSaltFromMetakey) (errorKey, k, &salt, &saltLen) != 1) { return -1; // error set by CRYPTO_PLUGIN_FUNCTION(getSaltFromMetakey)() } // remove salt as metakey because it will be encoded into the crypto payload keySetMeta (k, ELEKTRA_CRYPTO_META_SALT, NULL); // prepare the crypto header data const kdb_octet_t * content = keyValue (k); const kdb_unsigned_long_t contentLen = keyGetValueSize (k); kdb_octet_t flags; switch (keyIsString (k)) { case 1: // string flags = ELEKTRA_CRYPTO_FLAG_STRING; break; case -1: // NULL pointer flags = ELEKTRA_CRYPTO_FLAG_NULL; break; default: // binary flags = ELEKTRA_CRYPTO_FLAG_NONE; break; } // prepare buffer for cipher text output // NOTE the header goes into the first block if (contentLen % ELEKTRA_CRYPTO_GCRY_BLOCKSIZE == 0) { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 1; } else { outputLen = (contentLen / ELEKTRA_CRYPTO_GCRY_BLOCKSIZE) + 2; } outputLen *= ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; outputLen += ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; outputLen += sizeof (kdb_unsigned_long_t) + saltLen; kdb_octet_t * output = elektraMalloc (outputLen); if (!output) { ELEKTRA_SET_ERROR (87, errorKey, "Memory allocation failed"); elektraFree (salt); return -1; } kdb_octet_t * current = output; // output of the magic number memcpy (current, ELEKTRA_CRYPTO_MAGIC_NUMBER, ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN); current += ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; // encode the salt into the crypto payload memcpy (current, &saltLen, sizeof (kdb_unsigned_long_t)); current += sizeof (kdb_unsigned_long_t); memcpy (current, salt, saltLen); current += saltLen; // encrypt the header (1st block) using gcrypt's in-place encryption memcpy (current, &flags, sizeof (flags)); memcpy (current + sizeof (flags), &contentLen, sizeof (contentLen)); gcry_err = gcry_cipher_encrypt (*handle, current, ELEKTRA_CRYPTO_GCRY_BLOCKSIZE, NULL, 0); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_ENCRYPT_FAIL, errorKey, "Encryption failed because: %s", gcry_strerror (gcry_err)); memset (output, 0, outputLen); elektraFree (output); elektraFree (salt); return -1; } current += ELEKTRA_CRYPTO_GCRY_BLOCKSIZE; // encrypt the value using gcrypt's in-place encryption const size_t dataLen = outputLen - ELEKTRA_CRYPTO_GCRY_BLOCKSIZE - sizeof (kdb_unsigned_long_t) - saltLen - ELEKTRA_CRYPTO_MAGIC_NUMBER_LEN; if (contentLen) memcpy (current, content, contentLen); gcry_err = gcry_cipher_encrypt (*handle, current, dataLen, NULL, 0); if (gcry_err != 0) { ELEKTRA_SET_ERRORF (ELEKTRA_ERROR_CRYPTO_ENCRYPT_FAIL, errorKey, "Encryption failed because: %s", gcry_strerror (gcry_err)); memset (output, 0, outputLen); elektraFree (output); elektraFree (salt); return -1; } // write back the cipher text to the key keySetBinary (k, output, outputLen); memset (output, 0, outputLen); elektraFree (output); elektraFree (salt); return 1; }