Esempio n. 1
0
size_t Cipher::put(const unsigned char *data, size_t size)
{
    if(size % keys.iosize() || !bufaddr)
        return 0;

    size_t count = 0;

    while(bufsize && size + bufpos > bufsize) {
        size_t diff = bufsize - bufpos;
        count += put(data, diff);
        data += diff;
        size -= diff;
    }

    switch(bufmode) {
    case Cipher::ENCRYPT:
        gnutls_cipher_encrypt2((CIPHER_CTX)context, (void *)data, size, bufaddr + bufpos, size);
        break;
    case Cipher::DECRYPT:
        gnutls_cipher_decrypt2((CIPHER_CTX)context, data, size, bufaddr + bufpos, size);
    }

    count += size;
    if(!count) {
        release();
        return 0;
    }
    bufpos += size;
    if(bufsize && bufpos >= bufsize) {
        push(bufaddr, bufsize);
        bufpos = 0;
    }
    return count;
}
Esempio n. 2
0
static gboolean
purple_aes_cipher_gnutls_decrypt(const guchar *input, guchar *output, size_t len,
	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
	PurpleCipherBatchMode batch_mode)
{
	gnutls_cipher_hd_t handle;
	int ret;

	/* We have to simulate ECB mode, which is not supported by GnuTLS. */
	if (batch_mode == PURPLE_CIPHER_BATCH_MODE_ECB) {
		size_t i;
		for (i = 0; i < len / PURPLE_AES_BLOCK_SIZE; i++) {
			int offset = i * PURPLE_AES_BLOCK_SIZE;
			guchar iv_local[PURPLE_AES_BLOCK_SIZE];
			gboolean succ;

			memcpy(iv_local, iv, sizeof(iv_local));
			succ = purple_aes_cipher_gnutls_decrypt(
				input + offset, output + offset,
				PURPLE_AES_BLOCK_SIZE,
				iv_local, key, key_size,
				PURPLE_CIPHER_BATCH_MODE_CBC);
			if (!succ)
				return FALSE;
		}
		return TRUE;
	}

	handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
	if (handle == NULL)
		return FALSE;

	ret = gnutls_cipher_decrypt2(handle, input, len, output, len);
	gnutls_cipher_deinit(handle);

	if (ret != 0) {
		purple_debug_error("cipher-aes",
			"gnutls_cipher_decrypt2 failed: %d\n", ret);
		return FALSE;
	}

	return TRUE;
}
Esempio n. 3
0
static gboolean
purple_aes_cipher_gnutls_decrypt(const guchar *input, guchar *output, size_t len,
	guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
{
	gnutls_cipher_hd_t handle;
	int ret;

	handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
	if (handle == NULL)
		return FALSE;

	ret = gnutls_cipher_decrypt2(handle, input, len, output, len);
	gnutls_cipher_deinit(handle);

	if (ret != 0) {
		purple_debug_error("cipher-aes",
			"gnutls_cipher_decrypt2 failed: %d\n", ret);
		return FALSE;
	}

	return TRUE;
}
Esempio n. 4
0
gchar *password_decrypt_gnutls(const gchar *password,
		const gchar *decryption_passphrase)
{
	gchar **tokens, *tmp;
	gnutls_cipher_algorithm_t algo;
	gnutls_cipher_hd_t handle;
	gnutls_datum_t key, iv;
	int keylen, blocklen, ret;
	gsize len;
	unsigned char *buf;
	guint rounds;
	size_t commapos;

	g_return_val_if_fail(password != NULL, NULL);
	g_return_val_if_fail(decryption_passphrase != NULL, NULL);

	tokens = g_strsplit_set(password, "{}", 3);

	/* Parse the string, retrieving algorithm and encrypted data.
	 * We expect "{algorithm,rounds}base64encodedciphertext". */
	if (tokens[0] == NULL || strlen(tokens[0]) != 0 ||
			tokens[1] == NULL || strlen(tokens[1]) == 0 ||
			tokens[2] == NULL || strlen(tokens[2]) == 0) {
		debug_print("Garbled password string.\n");
		g_strfreev(tokens);
		return NULL;
	}

	commapos = strcspn(tokens[1], ",");
	if (commapos == strlen(tokens[1]) || commapos == 0) {
		debug_print("Garbled algorithm substring.\n");
		g_strfreev(tokens);
		return NULL;
	}

	buf = g_strndup(tokens[1], commapos);
	if ((algo = gnutls_cipher_get_id(buf)) == GNUTLS_CIPHER_UNKNOWN) {
		debug_print("Password string has unknown algorithm: '%s'\n", buf);
		g_free(buf);
		g_strfreev(tokens);
		return NULL;
	}
	g_free(buf);

	if ((rounds = atoi(tokens[1] + commapos + 1)) <= 0) {
		debug_print("Invalid number of rounds: %d\n", rounds);
		g_strfreev(tokens);
		return NULL;
	}

/*	ivlen = gnutls_cipher_get_iv_size(algo); */
	keylen = gnutls_cipher_get_key_size(algo);
	blocklen = gnutls_cipher_get_block_size(algo);
/*	digestlen = gnutls_hash_get_len(digest); */

	/* Take the passphrase and compute a key derivation of suitable
	 * length to be used as encryption key for our block cipher. */
	key.data = _make_key_deriv(decryption_passphrase, rounds, keylen);
	key.size = keylen;

	/* Prepare random IV for cipher */
	iv.data = malloc(IVLEN);
	iv.size = IVLEN;
	if (!get_random_bytes(iv.data, IVLEN)) {
		g_free(key.data);
		g_free(iv.data);
		g_strfreev(tokens);
		return NULL;
	}

	/* Prepare encrypted password string for decryption. */
	tmp = g_base64_decode(tokens[2], &len);
	g_strfreev(tokens);

	/* Initialize the decryption */
	ret = gnutls_cipher_init(&handle, algo, &key, &iv);
	if (ret < 0) {
		debug_print("Cipher init failed: %s\n", gnutls_strerror(ret));
		g_free(key.data);
		g_free(iv.data);
		return NULL;
	}

	buf = malloc(BUFSIZE + blocklen);
	memset(buf, 0, BUFSIZE + blocklen);
	ret = gnutls_cipher_decrypt2(handle, tmp, len,
			buf, BUFSIZE + blocklen);
	if (ret < 0) {
		debug_print("Decryption failed: %s\n", gnutls_strerror(ret));
		g_free(key.data);
		g_free(iv.data);
		g_free(buf);
		gnutls_cipher_deinit(handle);
		return NULL;
	}

	/* Cleanup */
	gnutls_cipher_deinit(handle);
	g_free(key.data);
	g_free(iv.data);

	tmp = g_strndup(buf + blocklen, MIN(strlen(buf + blocklen), BUFSIZE));
	g_free(buf);
	return tmp;
}
Esempio n. 5
0
char *
crypto_decrypt (const char *cipher,
                int key_type,
                GByteArray *data,
                const char *iv,
                const gsize iv_len,
                const char *key,
                const gsize key_len,
                gsize *out_len,
                GError **error)
{
	gnutls_cipher_hd_t ctx;
	gnutls_datum_t key_dt, iv_dt;
	int err;
	int cipher_mech, i;
	char *output = NULL;
	gboolean success = FALSE;
	gsize pad_len, real_iv_len;

	if (!strcmp (cipher, CIPHER_DES_EDE3_CBC)) {
		cipher_mech = GNUTLS_CIPHER_3DES_CBC;
		real_iv_len = SALT_LEN;
	} else if (!strcmp (cipher, CIPHER_DES_CBC)) {
		cipher_mech = GNUTLS_CIPHER_DES_CBC;
		real_iv_len = SALT_LEN;
	} else if (!strcmp (cipher, CIPHER_AES_CBC)) {
		cipher_mech = GNUTLS_CIPHER_AES_128_CBC;
		real_iv_len = 16;
	} else {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_UNKNOWN_CIPHER,
		             _("Private key cipher '%s' was unknown."),
		             cipher);
		return NULL;
	}

	if (iv_len < real_iv_len) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_RAW_IV_INVALID,
		             _("Invalid IV length (must be at least %zd)."),
		             real_iv_len);
		return NULL;
	}

	output = g_malloc0 (data->len);

	key_dt.data = (unsigned char *) key;
	key_dt.size = key_len;
	iv_dt.data = (unsigned char *) iv;
	iv_dt.size = iv_len;

	err = gnutls_cipher_init (&ctx, cipher_mech, &key_dt, &iv_dt);
	if (err < 0) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_INIT_FAILED,
		             _("Failed to initialize the decryption cipher context: %s (%s)"),
		             gnutls_strerror_name (err), gnutls_strerror (err));
		goto out;
	}

	err = gnutls_cipher_decrypt2 (ctx, data->data, data->len, output, data->len);
	if (err < 0) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
		             _("Failed to decrypt the private key: %s (%s)"),
		             gnutls_strerror_name (err), gnutls_strerror (err));
		goto out;
	}
	pad_len = output[data->len - 1];

	/* Check if the padding at the end of the decrypted data is valid */
	if (pad_len == 0 || pad_len > real_iv_len) {
		g_set_error (error, NM_CRYPTO_ERROR,
		             NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
		             _("Failed to decrypt the private key: unexpected padding length."));
		goto out;
	}

	/* Validate tail padding; last byte is the padding size, and all pad bytes
	 * should contain the padding size.
	 */
	for (i = 1; i <= pad_len; ++i) {
		if (output[data->len - i] != pad_len) {
			g_set_error (error, NM_CRYPTO_ERROR,
			             NM_CRYPTO_ERR_CIPHER_DECRYPT_FAILED,
			             _("Failed to decrypt the private key."));
			goto out;
		}
	}

	*out_len = data->len - pad_len;
	success = TRUE;

out:
	if (!success) {
		if (output) {
			/* Don't expose key material */
			memset (output, 0, data->len);
			g_free (output);
			output = NULL;
		}
	}
	gnutls_cipher_deinit (ctx);
	return output;
}