mirror of
https://gitlab.gnome.org/GNOME/libsecret.git
synced 2024-12-21 20:28:52 +00:00
28486191b2
This turns the `-Dgcrypt` build time option into a more generic `-Dcrypto` option, which enables user to choose which cryptographic library to link with. It currently supports libgcrypt (`libgcrypt`) and GnuTLS (`gnutls`); for the latter, GnuTLS 3.8.2 is the minimum required version. Signed-off-by: Daiki Ueno <dueno@src.gnome.org>
157 lines
3.4 KiB
C
157 lines
3.4 KiB
C
/* libsecret - GLib wrapper for Secret Service
|
|
*
|
|
* Copyright 2019 Red Hat, Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation; either version 2.1 of the licence or (at
|
|
* your option) any later version.
|
|
*
|
|
* See the included COPYING file for more information.
|
|
*
|
|
* Author: Daiki Ueno
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "egg-keyring1.h"
|
|
|
|
#include "egg/egg-secure-memory.h"
|
|
|
|
EGG_SECURE_DECLARE (egg_keyring1);
|
|
|
|
#include <gnutls/crypto.h>
|
|
#define PBKDF2_HASH_ALGO GNUTLS_MAC_SHA256
|
|
#define MAC_ALGO GNUTLS_MAC_SHA256
|
|
#define CIPHER_ALGO GNUTLS_CIPHER_AES_128_CBC
|
|
|
|
void
|
|
egg_keyring1_create_nonce (guint8 *nonce,
|
|
gsize nonce_size)
|
|
{
|
|
(void)gnutls_rnd (GNUTLS_RND_NONCE, nonce, nonce_size);
|
|
}
|
|
|
|
GBytes *
|
|
egg_keyring1_derive_key (const char *password,
|
|
gsize n_password,
|
|
GBytes *salt,
|
|
guint32 iteration_count)
|
|
{
|
|
gnutls_datum_t password_datum, salt_datum;
|
|
guint8 *buffer;
|
|
int ret;
|
|
|
|
password_datum.data = (void *)password;
|
|
password_datum.size = n_password;
|
|
|
|
salt_datum.data = (void *)g_bytes_get_data (salt, NULL);
|
|
salt_datum.size = g_bytes_get_size (salt);
|
|
|
|
buffer = egg_secure_alloc (KEY_SIZE);
|
|
g_return_val_if_fail (buffer, NULL);
|
|
|
|
ret = gnutls_pbkdf2 (PBKDF2_HASH_ALGO, &password_datum, &salt_datum,
|
|
iteration_count,
|
|
buffer, KEY_SIZE);
|
|
if (ret < 0) {
|
|
egg_secure_free (buffer);
|
|
return NULL;
|
|
}
|
|
|
|
return g_bytes_new_with_free_func (buffer,
|
|
KEY_SIZE,
|
|
egg_secure_free,
|
|
buffer);
|
|
}
|
|
|
|
gboolean
|
|
egg_keyring1_calculate_mac (GBytes *key,
|
|
const guint8 *value,
|
|
gsize n_value,
|
|
guint8 *buffer)
|
|
{
|
|
return gnutls_hmac_fast (MAC_ALGO,
|
|
g_bytes_get_data (key, NULL),
|
|
g_bytes_get_size (key),
|
|
value, n_value,
|
|
buffer) >= 0;
|
|
}
|
|
|
|
gboolean
|
|
egg_keyring1_verify_mac (GBytes *key,
|
|
const guint8 *value,
|
|
gsize n_value,
|
|
const guint8 *data)
|
|
{
|
|
guint8 buffer[MAC_SIZE];
|
|
guint8 status = 0;
|
|
gsize i;
|
|
|
|
if (!egg_keyring1_calculate_mac (key, value, n_value, buffer)) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < MAC_SIZE; i++) {
|
|
status |= data[i] ^ buffer[i];
|
|
}
|
|
|
|
return status == 0;
|
|
}
|
|
|
|
gboolean
|
|
egg_keyring1_decrypt (GBytes *key,
|
|
guint8 *data,
|
|
gsize n_data)
|
|
{
|
|
gnutls_cipher_hd_t hd = NULL;
|
|
int ret;
|
|
gsize n_secret;
|
|
gnutls_datum_t key_datum, iv_datum;
|
|
|
|
key_datum.data = (void *)g_bytes_get_data (key, &n_secret);
|
|
key_datum.size = n_secret;
|
|
|
|
iv_datum.data = data + n_data;
|
|
iv_datum.size = IV_SIZE;
|
|
|
|
ret = gnutls_cipher_init (&hd, CIPHER_ALGO, &key_datum, &iv_datum);
|
|
if (ret < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
ret = gnutls_cipher_decrypt2 (hd, data, n_data, data, n_data);
|
|
if (ret < 0) {
|
|
gnutls_cipher_deinit (hd);
|
|
return FALSE;
|
|
}
|
|
|
|
gnutls_cipher_deinit (hd);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
egg_keyring1_encrypt (GBytes *key,
|
|
guint8 *data,
|
|
gsize n_data)
|
|
{
|
|
gnutls_cipher_hd_t hd = NULL;
|
|
int ret;
|
|
gsize n_secret;
|
|
gnutls_datum_t key_datum, iv_datum;
|
|
|
|
key_datum.data = (void *)g_bytes_get_data (key, &n_secret);
|
|
key_datum.size = n_secret;
|
|
|
|
iv_datum.data = data + n_data;
|
|
iv_datum.size = IV_SIZE;
|
|
egg_keyring1_create_nonce (iv_datum.data, iv_datum.size);
|
|
|
|
ret = gnutls_cipher_init (&hd, CIPHER_ALGO, &key_datum, &iv_datum);
|
|
g_return_val_if_fail (ret >= 0, FALSE);
|
|
|
|
ret = gnutls_cipher_encrypt2 (hd, data, n_data, data, n_data);
|
|
gnutls_cipher_deinit (hd);
|
|
return ret < 0 ? FALSE : TRUE;
|
|
}
|