mirror of
https://gitlab.gnome.org/GNOME/libsecret.git
synced 2024-12-22 04:38:55 +00:00
Merge branch 'wip/dueno/crypto-backend' into 'master'
Support GnuTLS as an alternative crypto backend See merge request GNOME/libsecret!122
This commit is contained in:
commit
cc309e255a
@ -1,4 +1,4 @@
|
|||||||
image: registry.gitlab.gnome.org/gnome/libsecret/master:v2
|
image: registry.gitlab.gnome.org/gnome/libsecret/master:v3
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
@ -7,12 +7,21 @@ stages:
|
|||||||
variables:
|
variables:
|
||||||
CPPCHECK_OPTIONS: "--enable=warning --enable=style --enable=performance --enable=portability --std=c99 --template='{id}:{file}:{line},{severity},{message}'"
|
CPPCHECK_OPTIONS: "--enable=warning --enable=style --enable=performance --enable=portability --std=c99 --template='{id}:{file}:{line},{severity},{message}'"
|
||||||
|
|
||||||
|
.build:
|
||||||
|
parallel:
|
||||||
|
matrix:
|
||||||
|
- CRYPTO: libgcrypt
|
||||||
|
- CRYPTO: gnutls
|
||||||
|
- CRYPTO: disabled
|
||||||
|
|
||||||
fedora:Werror:
|
fedora:Werror:
|
||||||
stage: build
|
stage: build
|
||||||
|
extends:
|
||||||
|
- .build
|
||||||
before_script:
|
before_script:
|
||||||
- dbus-uuidgen --ensure
|
- dbus-uuidgen --ensure
|
||||||
script:
|
script:
|
||||||
- meson _build -Dwerror=true -Dc_args=-Wno-error=deprecated-declarations -Dgtk_doc=false
|
- meson _build -Dwerror=true -Dc_args=-Wno-error=deprecated-declarations -Dgtk_doc=false -Dcrypto=$CRYPTO
|
||||||
- meson compile -C _build
|
- meson compile -C _build
|
||||||
- eval `dbus-launch --sh-syntax`
|
- eval `dbus-launch --sh-syntax`
|
||||||
- meson test -C _build --print-errorlogs
|
- meson test -C _build --print-errorlogs
|
||||||
@ -23,11 +32,13 @@ fedora:Werror:
|
|||||||
|
|
||||||
fedora:asan:
|
fedora:asan:
|
||||||
stage: build
|
stage: build
|
||||||
|
extends:
|
||||||
|
- .build
|
||||||
before_script:
|
before_script:
|
||||||
- dbus-uuidgen --ensure
|
- dbus-uuidgen --ensure
|
||||||
script:
|
script:
|
||||||
- export LSAN_OPTIONS=suppressions=$PWD/build/lsan.supp
|
- export LSAN_OPTIONS=suppressions=$PWD/build/lsan.supp
|
||||||
- meson _build -Db_sanitize=address -Dgtk_doc=false -Dintrospection=false
|
- meson _build -Db_sanitize=address -Dgtk_doc=false -Dintrospection=false -Dcrypto=$CRYPTO
|
||||||
- meson compile -C _build
|
- meson compile -C _build
|
||||||
- eval `dbus-launch --sh-syntax`
|
- eval `dbus-launch --sh-syntax`
|
||||||
- meson test -C _build --print-errorlogs
|
- meson test -C _build --print-errorlogs
|
||||||
@ -38,10 +49,12 @@ fedora:asan:
|
|||||||
|
|
||||||
fedora:ubsan:
|
fedora:ubsan:
|
||||||
stage: build
|
stage: build
|
||||||
|
extends:
|
||||||
|
- .build
|
||||||
before_script:
|
before_script:
|
||||||
- dbus-uuidgen --ensure
|
- dbus-uuidgen --ensure
|
||||||
script:
|
script:
|
||||||
- meson _build -Db_sanitize=undefined -Dgtk_doc=false
|
- meson _build -Db_sanitize=undefined -Dgtk_doc=false -Dcrypto=$CRYPTO
|
||||||
- meson compile -C _build
|
- meson compile -C _build
|
||||||
- eval `dbus-launch --sh-syntax`
|
- eval `dbus-launch --sh-syntax`
|
||||||
- meson test -C _build --print-errorlogs
|
- meson test -C _build --print-errorlogs
|
||||||
@ -52,10 +65,12 @@ fedora:ubsan:
|
|||||||
|
|
||||||
fedora-static-analyzers/test:
|
fedora-static-analyzers/test:
|
||||||
stage: build
|
stage: build
|
||||||
|
extends:
|
||||||
|
- .build
|
||||||
before_script:
|
before_script:
|
||||||
- dbus-uuidgen --ensure
|
- dbus-uuidgen --ensure
|
||||||
script:
|
script:
|
||||||
- meson _build -Dgtk_doc=false
|
- meson _build -Dgtk_doc=false -Dcrypto=$CRYPTO
|
||||||
- meson compile -C _build --ninja-args scan-build
|
- meson compile -C _build --ninja-args scan-build
|
||||||
- cppcheck --force -q $CPPCHECK_OPTIONS libsecret/ egg/ tool/
|
- cppcheck --force -q $CPPCHECK_OPTIONS libsecret/ egg/ tool/
|
||||||
artifacts:
|
artifacts:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM fedora:38
|
FROM fedora:39
|
||||||
|
|
||||||
RUN dnf update -y \
|
RUN dnf update -y \
|
||||||
&& dnf install -y \
|
&& dnf install -y \
|
||||||
@ -10,6 +10,7 @@ RUN dnf update -y \
|
|||||||
gi-docgen \
|
gi-docgen \
|
||||||
git \
|
git \
|
||||||
glib2-devel \
|
glib2-devel \
|
||||||
|
gnutls-devel \
|
||||||
gobject-introspection-devel \
|
gobject-introspection-devel \
|
||||||
lcov \
|
lcov \
|
||||||
libasan \
|
libasan \
|
||||||
|
261
egg/egg-dh-gnutls.c
Normal file
261
egg/egg-dh-gnutls.c
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
* libsecret
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Daiki Ueno
|
||||||
|
*
|
||||||
|
* 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 License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received copies of the GNU General Public License and
|
||||||
|
* the GNU Lesser General Public License along with this program. If
|
||||||
|
* not, see http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
* Author: Daiki Ueno
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "egg-dh.h"
|
||||||
|
|
||||||
|
/* Enabling this is a complete security compromise */
|
||||||
|
#define DEBUG_DH_SECRET 0
|
||||||
|
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#include <gnutls/abstract.h>
|
||||||
|
|
||||||
|
struct egg_dh_params {
|
||||||
|
gnutls_dh_params_t inner;
|
||||||
|
guint bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct egg_dh_pubkey {
|
||||||
|
gnutls_pubkey_t inner;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct egg_dh_privkey {
|
||||||
|
gnutls_privkey_t inner;
|
||||||
|
};
|
||||||
|
|
||||||
|
egg_dh_params *
|
||||||
|
egg_dh_default_params (const gchar *name)
|
||||||
|
{
|
||||||
|
const egg_dh_group *group;
|
||||||
|
egg_dh_params *params;
|
||||||
|
|
||||||
|
g_return_val_if_fail (name, NULL);
|
||||||
|
|
||||||
|
for (group = egg_dh_groups; group->name; ++group) {
|
||||||
|
if (g_str_equal (group->name, name)) {
|
||||||
|
gnutls_dh_params_t inner;
|
||||||
|
gnutls_datum_t prime, generator;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = gnutls_dh_params_init (&inner);
|
||||||
|
if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
prime.data = (void *)group->prime;
|
||||||
|
prime.size = group->n_prime;
|
||||||
|
generator.data = (void *)group->base;
|
||||||
|
generator.size = group->n_base;
|
||||||
|
|
||||||
|
ret = gnutls_dh_params_import_raw (inner,
|
||||||
|
&prime,
|
||||||
|
&generator);
|
||||||
|
if (ret < 0) {
|
||||||
|
gnutls_dh_params_deinit (inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
params = g_new (struct egg_dh_params, 1);
|
||||||
|
if (!params) {
|
||||||
|
gnutls_dh_params_deinit (inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
params->inner = g_steal_pointer (&inner);
|
||||||
|
params->bits = group->bits;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
egg_dh_gen_pair (egg_dh_params *params, guint bits,
|
||||||
|
egg_dh_pubkey **pub, egg_dh_privkey **priv)
|
||||||
|
{
|
||||||
|
gnutls_pubkey_t pub_inner = NULL;
|
||||||
|
gnutls_privkey_t priv_inner = NULL;
|
||||||
|
egg_dh_pubkey *pub_outer = NULL;
|
||||||
|
egg_dh_privkey *priv_outer = NULL;
|
||||||
|
gnutls_keygen_data_st data;
|
||||||
|
gboolean ok = FALSE;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
g_return_val_if_fail (params, FALSE);
|
||||||
|
g_return_val_if_fail (pub, FALSE);
|
||||||
|
g_return_val_if_fail (priv, FALSE);
|
||||||
|
|
||||||
|
if (bits == 0)
|
||||||
|
bits = params->bits;
|
||||||
|
else if (bits > params->bits)
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
|
||||||
|
ret = gnutls_privkey_init (&priv_inner);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
data.type = GNUTLS_KEYGEN_DH;
|
||||||
|
data.data = (void *)params->inner;
|
||||||
|
|
||||||
|
ret = gnutls_privkey_generate2 (priv_inner, GNUTLS_PK_DH, bits, 0,
|
||||||
|
&data, 1);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = gnutls_pubkey_init (&pub_inner);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = gnutls_pubkey_import_privkey (pub_inner, priv_inner, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
pub_outer = g_new0 (struct egg_dh_pubkey, 1);
|
||||||
|
if (!pub_outer)
|
||||||
|
goto out;
|
||||||
|
pub_outer->inner = g_steal_pointer (&pub_inner);
|
||||||
|
|
||||||
|
priv_outer = g_new0 (struct egg_dh_privkey, 1);
|
||||||
|
if (!priv_outer)
|
||||||
|
goto out;
|
||||||
|
priv_outer->inner = g_steal_pointer (&priv_inner);
|
||||||
|
|
||||||
|
*pub = g_steal_pointer (&pub_outer);
|
||||||
|
*priv = g_steal_pointer (&priv_outer);
|
||||||
|
|
||||||
|
ok = TRUE;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (priv_inner)
|
||||||
|
gnutls_privkey_deinit (priv_inner);
|
||||||
|
if (pub_inner)
|
||||||
|
gnutls_pubkey_deinit (pub_inner);
|
||||||
|
|
||||||
|
egg_dh_privkey_free (priv_outer);
|
||||||
|
egg_dh_pubkey_free (pub_outer);
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv,
|
||||||
|
egg_dh_params *params)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
gnutls_datum_t k;
|
||||||
|
#if DEBUG_DH_SECRET
|
||||||
|
gnutls_datum_t h;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_return_val_if_fail (peer, NULL);
|
||||||
|
g_return_val_if_fail (priv, NULL);
|
||||||
|
g_return_val_if_fail (params, NULL);
|
||||||
|
|
||||||
|
ret = gnutls_privkey_derive_secret (priv->inner, peer->inner,
|
||||||
|
NULL, &k, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#if DEBUG_DH_SECRET
|
||||||
|
ret = gnutls_hex_encode2 (&k, &h);
|
||||||
|
g_assert (ret >= 0);
|
||||||
|
g_printerr ("DH SECRET: %s\n", h.data);
|
||||||
|
gnutls_free (h.data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return g_bytes_new_with_free_func (k.data, k.size,
|
||||||
|
(GDestroyNotify)gnutls_free,
|
||||||
|
k.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
egg_dh_params_free (egg_dh_params *params)
|
||||||
|
{
|
||||||
|
gnutls_dh_params_deinit (params->inner);
|
||||||
|
g_free (params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
egg_dh_pubkey_free (egg_dh_pubkey *pubkey)
|
||||||
|
{
|
||||||
|
if (!pubkey)
|
||||||
|
return;
|
||||||
|
if (pubkey->inner)
|
||||||
|
gnutls_pubkey_deinit (pubkey->inner);
|
||||||
|
g_free (pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
egg_dh_privkey_free (egg_dh_privkey *privkey)
|
||||||
|
{
|
||||||
|
if (!privkey)
|
||||||
|
return;
|
||||||
|
if (privkey->inner)
|
||||||
|
gnutls_privkey_deinit (privkey->inner);
|
||||||
|
g_free (privkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
egg_dh_pubkey_export (const egg_dh_pubkey *pubkey)
|
||||||
|
{
|
||||||
|
gnutls_datum_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = gnutls_pubkey_export_dh_raw (pubkey->inner, NULL, &data, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_bytes_new_with_free_func (data.data, data.size,
|
||||||
|
(GDestroyNotify)gnutls_free,
|
||||||
|
data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
egg_dh_pubkey *
|
||||||
|
egg_dh_pubkey_new_from_bytes (const egg_dh_params *params, GBytes *bytes)
|
||||||
|
{
|
||||||
|
egg_dh_pubkey *pub;
|
||||||
|
gnutls_pubkey_t inner;
|
||||||
|
gnutls_datum_t data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = gnutls_pubkey_init (&inner);
|
||||||
|
if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data.data = (void *)g_bytes_get_data (bytes, NULL);
|
||||||
|
data.size = g_bytes_get_size (bytes);
|
||||||
|
|
||||||
|
ret = gnutls_pubkey_import_dh_raw (inner, params->inner, &data);
|
||||||
|
if (ret < 0) {
|
||||||
|
gnutls_pubkey_deinit (inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub = g_new (struct egg_dh_pubkey, 1);
|
||||||
|
if (!pub) {
|
||||||
|
gnutls_pubkey_deinit (inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub->inner = g_steal_pointer (&inner);
|
||||||
|
return pub;
|
||||||
|
}
|
278
egg/egg-dh-libgcrypt.c
Normal file
278
egg/egg-dh-libgcrypt.c
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* gnome-keyring
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 Stefan Walter
|
||||||
|
*
|
||||||
|
* 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 License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received copies of the GNU General Public License and
|
||||||
|
* the GNU Lesser General Public License along with this program. If
|
||||||
|
* not, see http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
* Author: Stef Walter <stefw@thewalter.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "egg-dh.h"
|
||||||
|
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#include "egg-secure-memory.h"
|
||||||
|
|
||||||
|
/* Enabling this is a complete security compromise */
|
||||||
|
#define DEBUG_DH_SECRET 0
|
||||||
|
|
||||||
|
EGG_SECURE_DECLARE (dh);
|
||||||
|
|
||||||
|
struct egg_dh_params {
|
||||||
|
gcry_mpi_t prime;
|
||||||
|
gcry_mpi_t base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct egg_dh_pubkey {
|
||||||
|
gcry_mpi_t inner;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct egg_dh_privkey {
|
||||||
|
gcry_mpi_t inner;
|
||||||
|
};
|
||||||
|
|
||||||
|
egg_dh_params *
|
||||||
|
egg_dh_default_params (const gchar *name)
|
||||||
|
{
|
||||||
|
const egg_dh_group *group;
|
||||||
|
gcry_error_t gcry;
|
||||||
|
gcry_mpi_t prime = NULL, base = NULL;
|
||||||
|
egg_dh_params *params = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (name, NULL);
|
||||||
|
|
||||||
|
for (group = egg_dh_groups; group->name; ++group)
|
||||||
|
if (g_str_equal (group->name, name))
|
||||||
|
break;
|
||||||
|
if (!group->name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
gcry = gcry_mpi_scan (&prime, GCRYMPI_FMT_USG,
|
||||||
|
group->prime, group->n_prime, NULL);
|
||||||
|
g_return_val_if_fail (gcry == 0, NULL);
|
||||||
|
g_return_val_if_fail (gcry_mpi_get_nbits (prime) == group->bits, NULL);
|
||||||
|
|
||||||
|
gcry = gcry_mpi_scan (&base, GCRYMPI_FMT_USG,
|
||||||
|
group->base, group->n_base, NULL);
|
||||||
|
g_return_val_if_fail (gcry == 0, NULL);
|
||||||
|
|
||||||
|
params = g_new (struct egg_dh_params, 1);
|
||||||
|
if (!params)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
params->prime = g_steal_pointer (&prime);
|
||||||
|
params->base = g_steal_pointer (&base);
|
||||||
|
|
||||||
|
error:
|
||||||
|
gcry_mpi_release (prime);
|
||||||
|
gcry_mpi_release (base);
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
egg_dh_gen_pair (egg_dh_params *params, guint bits,
|
||||||
|
egg_dh_pubkey **pub, egg_dh_privkey **priv)
|
||||||
|
{
|
||||||
|
guint pbits;
|
||||||
|
gcry_mpi_t pub_inner = NULL, priv_inner = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (params, FALSE);
|
||||||
|
g_return_val_if_fail (pub, FALSE);
|
||||||
|
g_return_val_if_fail (priv, FALSE);
|
||||||
|
|
||||||
|
*pub = NULL;
|
||||||
|
*priv = NULL;
|
||||||
|
|
||||||
|
pbits = gcry_mpi_get_nbits (params->prime);
|
||||||
|
g_return_val_if_fail (pbits > 1, FALSE);
|
||||||
|
|
||||||
|
if (bits == 0) {
|
||||||
|
bits = pbits;
|
||||||
|
} else if (bits > pbits) {
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a strong random number of bits, and not zero.
|
||||||
|
* gcry_mpi_randomize bumps up to the next byte. Since we
|
||||||
|
* need to have a value less than half of prime, we make sure
|
||||||
|
* we bump down.
|
||||||
|
*/
|
||||||
|
priv_inner = gcry_mpi_snew (bits);
|
||||||
|
g_return_val_if_fail (priv_inner, FALSE);
|
||||||
|
while (gcry_mpi_cmp_ui (priv_inner, 0) == 0)
|
||||||
|
gcry_mpi_randomize (priv_inner, bits, GCRY_STRONG_RANDOM);
|
||||||
|
|
||||||
|
/* Secret key value must be less than half of p */
|
||||||
|
if (gcry_mpi_get_nbits (priv_inner) > bits)
|
||||||
|
gcry_mpi_clear_highbit (priv_inner, bits);
|
||||||
|
if (gcry_mpi_get_nbits (priv_inner) > pbits - 1)
|
||||||
|
gcry_mpi_clear_highbit (priv_inner, pbits - 1);
|
||||||
|
g_assert (gcry_mpi_cmp (params->prime, priv_inner) > 0);
|
||||||
|
|
||||||
|
pub_inner = gcry_mpi_new (gcry_mpi_get_nbits (priv_inner));
|
||||||
|
if (!pub_inner)
|
||||||
|
goto error;
|
||||||
|
gcry_mpi_powm (pub_inner, params->base, priv_inner, params->prime);
|
||||||
|
|
||||||
|
*priv = g_new0 (struct egg_dh_privkey, 1);
|
||||||
|
if (!*priv)
|
||||||
|
goto error;
|
||||||
|
(*priv)->inner = g_steal_pointer (&priv_inner);
|
||||||
|
|
||||||
|
*pub = g_new0 (struct egg_dh_pubkey, 1);
|
||||||
|
if (!*pub)
|
||||||
|
goto error;
|
||||||
|
(*pub)->inner = g_steal_pointer (&pub_inner);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
error:
|
||||||
|
egg_dh_privkey_free (*priv);
|
||||||
|
egg_dh_pubkey_free (*pub);
|
||||||
|
|
||||||
|
gcry_mpi_release (priv_inner);
|
||||||
|
gcry_mpi_release (pub_inner);
|
||||||
|
|
||||||
|
g_return_val_if_reached (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
egg_dh_gen_secret (egg_dh_pubkey *peer, egg_dh_privkey *priv,
|
||||||
|
egg_dh_params *params)
|
||||||
|
{
|
||||||
|
gcry_error_t gcry;
|
||||||
|
guchar *value;
|
||||||
|
gsize n_prime;
|
||||||
|
gsize n_value;
|
||||||
|
gcry_mpi_t k;
|
||||||
|
gint bits;
|
||||||
|
|
||||||
|
g_return_val_if_fail (peer, NULL);
|
||||||
|
g_return_val_if_fail (priv, NULL);
|
||||||
|
g_return_val_if_fail (params, NULL);
|
||||||
|
|
||||||
|
bits = gcry_mpi_get_nbits (params->prime);
|
||||||
|
g_return_val_if_fail (bits >= 0, NULL);
|
||||||
|
|
||||||
|
k = gcry_mpi_snew (bits);
|
||||||
|
g_return_val_if_fail (k, NULL);
|
||||||
|
gcry_mpi_powm (k, peer->inner, priv->inner, params->prime);
|
||||||
|
|
||||||
|
/* Write out the secret */
|
||||||
|
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_prime, params->prime);
|
||||||
|
g_return_val_if_fail (gcry == 0, NULL);
|
||||||
|
|
||||||
|
value = egg_secure_alloc (n_prime);
|
||||||
|
if (!value)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_prime, &n_value, k);
|
||||||
|
g_return_val_if_fail (gcry == 0, NULL);
|
||||||
|
|
||||||
|
/* Pad the secret with zero bytes to match length of prime in bytes. */
|
||||||
|
if (n_value < n_prime) {
|
||||||
|
memmove (value + (n_prime - n_value), value, n_value);
|
||||||
|
memset (value, 0, (n_prime - n_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG_DH_SECRET
|
||||||
|
g_printerr ("DH SECRET: ");
|
||||||
|
gcry_mpi_dump (k);
|
||||||
|
#endif
|
||||||
|
gcry_mpi_release (k);
|
||||||
|
|
||||||
|
#if DEBUG_DH_SECRET
|
||||||
|
gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, n_prime, NULL);
|
||||||
|
g_printerr ("RAW SECRET: ");
|
||||||
|
gcry_mpi_dump (k);
|
||||||
|
gcry_mpi_release (k);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return g_bytes_new_with_free_func (value, n_prime,
|
||||||
|
(GDestroyNotify)egg_secure_free,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
egg_dh_params_free (egg_dh_params *params)
|
||||||
|
{
|
||||||
|
if (!params)
|
||||||
|
return;
|
||||||
|
gcry_mpi_release (params->prime);
|
||||||
|
gcry_mpi_release (params->base);
|
||||||
|
g_free (params);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
egg_dh_pubkey_free (egg_dh_pubkey *pubkey)
|
||||||
|
{
|
||||||
|
if (!pubkey)
|
||||||
|
return;
|
||||||
|
if (pubkey->inner)
|
||||||
|
gcry_mpi_release (pubkey->inner);
|
||||||
|
g_free (pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
egg_dh_privkey_free (egg_dh_privkey *privkey)
|
||||||
|
{
|
||||||
|
if (!privkey)
|
||||||
|
return;
|
||||||
|
if (privkey->inner)
|
||||||
|
gcry_mpi_release (privkey->inner);
|
||||||
|
g_free (privkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
egg_dh_pubkey_export (const egg_dh_pubkey *pubkey)
|
||||||
|
{
|
||||||
|
gcry_error_t gcry;
|
||||||
|
unsigned char *buffer;
|
||||||
|
size_t n_buffer;
|
||||||
|
|
||||||
|
gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer,
|
||||||
|
pubkey->inner);
|
||||||
|
g_return_val_if_fail (gcry == 0, NULL);
|
||||||
|
|
||||||
|
return g_bytes_new_with_free_func (buffer, n_buffer,
|
||||||
|
gcry_free, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
egg_dh_pubkey *
|
||||||
|
egg_dh_pubkey_new_from_bytes (const egg_dh_params *params,
|
||||||
|
GBytes *bytes)
|
||||||
|
{
|
||||||
|
gcry_error_t gcry;
|
||||||
|
gcry_mpi_t inner;
|
||||||
|
egg_dh_pubkey *pub;
|
||||||
|
|
||||||
|
gcry = gcry_mpi_scan (&inner, GCRYMPI_FMT_USG,
|
||||||
|
g_bytes_get_data (bytes, NULL),
|
||||||
|
g_bytes_get_size (bytes),
|
||||||
|
NULL);
|
||||||
|
if (gcry != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pub = g_new (struct egg_dh_pubkey, 1);
|
||||||
|
if (!pub) {
|
||||||
|
gcry_mpi_release (inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub->inner = inner;
|
||||||
|
return pub;
|
||||||
|
}
|
152
egg/egg-dh.c
152
egg/egg-dh.c
@ -13,10 +13,9 @@
|
|||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received copies of the GNU General Public License and
|
||||||
* License along with this program; if not, write to the Free Software
|
* the GNU Lesser General Public License along with this program. If
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
* not, see http://www.gnu.org/licenses/.
|
||||||
* MA 02110-1301 USA
|
|
||||||
*
|
*
|
||||||
* Author: Stef Walter <stefw@thewalter.net>
|
* Author: Stef Walter <stefw@thewalter.net>
|
||||||
*/
|
*/
|
||||||
@ -24,21 +23,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "egg-dh.h"
|
#include "egg-dh.h"
|
||||||
#include "egg-secure-memory.h"
|
|
||||||
|
|
||||||
/* Enabling this is a complete security compromise */
|
|
||||||
#define DEBUG_DH_SECRET 0
|
|
||||||
|
|
||||||
EGG_SECURE_DECLARE (dh);
|
|
||||||
|
|
||||||
typedef struct _DHGroup {
|
|
||||||
const gchar *name;
|
|
||||||
guint bits;
|
|
||||||
const guchar *prime;
|
|
||||||
gsize n_prime;
|
|
||||||
const guchar base[1];
|
|
||||||
gsize n_base;
|
|
||||||
} DHGroup;
|
|
||||||
|
|
||||||
static const guchar dh_group_768_prime[] = {
|
static const guchar dh_group_768_prime[] = {
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||||
@ -171,7 +155,7 @@ static const guchar dh_group_8192_prime[] = {
|
|||||||
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const DHGroup dh_groups[] = {
|
const egg_dh_group egg_dh_groups[] = {
|
||||||
{
|
{
|
||||||
"ietf-ike-grp-modp-768", 768,
|
"ietf-ike-grp-modp-768", 768,
|
||||||
dh_group_768_prime, G_N_ELEMENTS (dh_group_768_prime),
|
dh_group_768_prime, G_N_ELEMENTS (dh_group_768_prime),
|
||||||
@ -216,7 +200,7 @@ gboolean
|
|||||||
egg_dh_default_params_raw (const gchar *name, gconstpointer *prime,
|
egg_dh_default_params_raw (const gchar *name, gconstpointer *prime,
|
||||||
gsize *n_prime, gconstpointer *base, gsize *n_base)
|
gsize *n_prime, gconstpointer *base, gsize *n_base)
|
||||||
{
|
{
|
||||||
const DHGroup *group;
|
const egg_dh_group *group;
|
||||||
|
|
||||||
g_return_val_if_fail (name, FALSE);
|
g_return_val_if_fail (name, FALSE);
|
||||||
g_return_val_if_fail (prime, FALSE);
|
g_return_val_if_fail (prime, FALSE);
|
||||||
@ -224,7 +208,7 @@ egg_dh_default_params_raw (const gchar *name, gconstpointer *prime,
|
|||||||
g_return_val_if_fail (base, FALSE);
|
g_return_val_if_fail (base, FALSE);
|
||||||
g_return_val_if_fail (n_base, FALSE);
|
g_return_val_if_fail (n_base, FALSE);
|
||||||
|
|
||||||
for (group = dh_groups; group->name; ++group) {
|
for (group = egg_dh_groups; group->name; ++group) {
|
||||||
if (g_str_equal (group->name, name)) {
|
if (g_str_equal (group->name, name)) {
|
||||||
*prime = group->prime;
|
*prime = group->prime;
|
||||||
*n_prime = group->n_prime;
|
*n_prime = group->n_prime;
|
||||||
@ -236,127 +220,3 @@ egg_dh_default_params_raw (const gchar *name, gconstpointer *prime,
|
|||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
|
||||||
egg_dh_default_params (const gchar *name, gcry_mpi_t *prime, gcry_mpi_t *base)
|
|
||||||
{
|
|
||||||
const DHGroup *group;
|
|
||||||
gcry_error_t gcry;
|
|
||||||
|
|
||||||
g_return_val_if_fail (name, FALSE);
|
|
||||||
|
|
||||||
for (group = dh_groups; group->name; ++group) {
|
|
||||||
if (g_str_equal (group->name, name)) {
|
|
||||||
if (prime) {
|
|
||||||
gcry = gcry_mpi_scan (prime, GCRYMPI_FMT_USG, group->prime, group->n_prime, NULL);
|
|
||||||
g_return_val_if_fail (gcry == 0, FALSE);
|
|
||||||
g_return_val_if_fail (gcry_mpi_get_nbits (*prime) == group->bits, FALSE);
|
|
||||||
}
|
|
||||||
if (base) {
|
|
||||||
gcry = gcry_mpi_scan (base, GCRYMPI_FMT_USG, group->base, group->n_base, NULL);
|
|
||||||
g_return_val_if_fail (gcry == 0, FALSE);
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
egg_dh_gen_pair (gcry_mpi_t prime, gcry_mpi_t base, guint bits,
|
|
||||||
gcry_mpi_t *pub, gcry_mpi_t *priv)
|
|
||||||
{
|
|
||||||
guint pbits;
|
|
||||||
|
|
||||||
g_return_val_if_fail (prime, FALSE);
|
|
||||||
g_return_val_if_fail (base, FALSE);
|
|
||||||
g_return_val_if_fail (pub, FALSE);
|
|
||||||
g_return_val_if_fail (priv, FALSE);
|
|
||||||
|
|
||||||
pbits = gcry_mpi_get_nbits (prime);
|
|
||||||
g_return_val_if_fail (pbits > 1, FALSE);
|
|
||||||
|
|
||||||
if (bits == 0) {
|
|
||||||
bits = pbits;
|
|
||||||
} else if (bits > pbits) {
|
|
||||||
g_return_val_if_reached (FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate a strong random number of bits, and not zero.
|
|
||||||
* gcry_mpi_randomize bumps up to the next byte. Since we
|
|
||||||
* need to have a value less than half of prime, we make sure
|
|
||||||
* we bump down.
|
|
||||||
*/
|
|
||||||
*priv = gcry_mpi_snew (bits);
|
|
||||||
g_return_val_if_fail (*priv, FALSE);
|
|
||||||
while (gcry_mpi_cmp_ui (*priv, 0) == 0)
|
|
||||||
gcry_mpi_randomize (*priv, bits, GCRY_STRONG_RANDOM);
|
|
||||||
|
|
||||||
/* Secret key value must be less than half of p */
|
|
||||||
if (gcry_mpi_get_nbits (*priv) > bits)
|
|
||||||
gcry_mpi_clear_highbit (*priv, bits);
|
|
||||||
if (gcry_mpi_get_nbits (*priv) > pbits - 1)
|
|
||||||
gcry_mpi_clear_highbit (*priv, pbits - 1);
|
|
||||||
g_assert (gcry_mpi_cmp (prime, *priv) > 0);
|
|
||||||
|
|
||||||
*pub = gcry_mpi_new (gcry_mpi_get_nbits (*priv));
|
|
||||||
g_return_val_if_fail (*pub, FALSE);
|
|
||||||
gcry_mpi_powm (*pub, base, *priv, prime);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpointer
|
|
||||||
egg_dh_gen_secret (gcry_mpi_t peer, gcry_mpi_t priv,
|
|
||||||
gcry_mpi_t prime, gsize *bytes)
|
|
||||||
{
|
|
||||||
gcry_error_t gcry;
|
|
||||||
guchar *value;
|
|
||||||
gsize n_prime;
|
|
||||||
gsize n_value;
|
|
||||||
gcry_mpi_t k;
|
|
||||||
gint bits;
|
|
||||||
|
|
||||||
g_return_val_if_fail (peer, NULL);
|
|
||||||
g_return_val_if_fail (priv, NULL);
|
|
||||||
g_return_val_if_fail (prime, NULL);
|
|
||||||
|
|
||||||
bits = gcry_mpi_get_nbits (prime);
|
|
||||||
g_return_val_if_fail (bits >= 0, NULL);
|
|
||||||
|
|
||||||
k = gcry_mpi_snew (bits);
|
|
||||||
g_return_val_if_fail (k, NULL);
|
|
||||||
gcry_mpi_powm (k, peer, priv, prime);
|
|
||||||
|
|
||||||
/* Write out the secret */
|
|
||||||
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_prime, prime);
|
|
||||||
g_return_val_if_fail (gcry == 0, NULL);
|
|
||||||
value = egg_secure_alloc (n_prime);
|
|
||||||
gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_prime, &n_value, k);
|
|
||||||
g_return_val_if_fail (gcry == 0, NULL);
|
|
||||||
|
|
||||||
/* Pad the secret with zero bytes to match length of prime in bytes. */
|
|
||||||
if (n_value < n_prime) {
|
|
||||||
memmove (value + (n_prime - n_value), value, n_value);
|
|
||||||
memset (value, 0, (n_prime - n_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG_DH_SECRET
|
|
||||||
g_printerr ("DH SECRET: ");
|
|
||||||
gcry_mpi_dump (k);
|
|
||||||
#endif
|
|
||||||
gcry_mpi_release (k);
|
|
||||||
|
|
||||||
*bytes = n_prime;
|
|
||||||
|
|
||||||
#if DEBUG_DH_SECRET
|
|
||||||
gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, bytes, NULL);
|
|
||||||
g_printerr ("RAW SECRET: ");
|
|
||||||
gcry_mpi_dump (k);
|
|
||||||
gcry_mpi_release (k);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
41
egg/egg-dh.h
41
egg/egg-dh.h
@ -26,11 +26,22 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include <gcrypt.h>
|
typedef struct egg_dh_params egg_dh_params;
|
||||||
|
typedef struct egg_dh_pubkey egg_dh_pubkey;
|
||||||
|
typedef struct egg_dh_privkey egg_dh_privkey;
|
||||||
|
|
||||||
gboolean egg_dh_default_params (const gchar *name,
|
typedef struct egg_dh_group {
|
||||||
gcry_mpi_t *prime,
|
const gchar *name;
|
||||||
gcry_mpi_t *base);
|
guint bits;
|
||||||
|
const guchar *prime;
|
||||||
|
gsize n_prime;
|
||||||
|
const guchar base[1];
|
||||||
|
gsize n_base;
|
||||||
|
} egg_dh_group;
|
||||||
|
|
||||||
|
extern const egg_dh_group egg_dh_groups[];
|
||||||
|
|
||||||
|
egg_dh_params *egg_dh_default_params (const gchar *name);
|
||||||
|
|
||||||
gboolean egg_dh_default_params_raw (const gchar *name,
|
gboolean egg_dh_default_params_raw (const gchar *name,
|
||||||
gconstpointer *prime,
|
gconstpointer *prime,
|
||||||
@ -38,15 +49,21 @@ gboolean egg_dh_default_params_raw (const gchar *name
|
|||||||
gconstpointer *base,
|
gconstpointer *base,
|
||||||
gsize *n_base);
|
gsize *n_base);
|
||||||
|
|
||||||
gboolean egg_dh_gen_pair (gcry_mpi_t prime,
|
gboolean egg_dh_gen_pair (egg_dh_params *params,
|
||||||
gcry_mpi_t base,
|
|
||||||
guint bits,
|
guint bits,
|
||||||
gcry_mpi_t *pub,
|
egg_dh_pubkey **pub,
|
||||||
gcry_mpi_t *priv);
|
egg_dh_privkey **priv);
|
||||||
|
|
||||||
gpointer egg_dh_gen_secret (gcry_mpi_t peer,
|
GBytes *egg_dh_gen_secret (egg_dh_pubkey *peer,
|
||||||
gcry_mpi_t priv,
|
egg_dh_privkey *priv,
|
||||||
gcry_mpi_t prime,
|
egg_dh_params *prime);
|
||||||
gsize *bytes);
|
|
||||||
|
void egg_dh_params_free (egg_dh_params *params);
|
||||||
|
void egg_dh_pubkey_free (egg_dh_pubkey *pubkey);
|
||||||
|
void egg_dh_privkey_free (egg_dh_privkey *privkey);
|
||||||
|
|
||||||
|
GBytes *egg_dh_pubkey_export (const egg_dh_pubkey *pubkey);
|
||||||
|
egg_dh_pubkey *egg_dh_pubkey_new_from_bytes (const egg_dh_params *params,
|
||||||
|
GBytes *bytes);
|
||||||
|
|
||||||
#endif /* EGG_DH_H_ */
|
#endif /* EGG_DH_H_ */
|
||||||
|
110
egg/egg-hkdf-gnutls.c
Normal file
110
egg/egg-hkdf-gnutls.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* libsecret
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Daiki Ueno
|
||||||
|
*
|
||||||
|
* 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 License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received copies of the GNU General Public License and
|
||||||
|
* the GNU Lesser General Public License along with this program. If
|
||||||
|
* not, see http://www.gnu.org/licenses/.
|
||||||
|
*
|
||||||
|
* Author: Daiki Ueno
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "egg-hkdf.h"
|
||||||
|
|
||||||
|
#include "egg-secure-memory.h"
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
|
|
||||||
|
EGG_SECURE_DECLARE (hkdf);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
egg_hkdf_perform (const gchar *hash_algo, gconstpointer input, gsize n_input,
|
||||||
|
gconstpointer salt, gsize n_salt, gconstpointer info,
|
||||||
|
gsize n_info, gpointer output, gsize n_output)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
gchar *name;
|
||||||
|
gnutls_mac_algorithm_t algo;
|
||||||
|
} hash_algos[] = {
|
||||||
|
{ "sha1", GNUTLS_MAC_SHA1 },
|
||||||
|
{ "sha256", GNUTLS_MAC_SHA256 },
|
||||||
|
{ NULL, }
|
||||||
|
};
|
||||||
|
gnutls_mac_algorithm_t algo = GNUTLS_MAC_UNKNOWN;
|
||||||
|
gnutls_datum_t input_datum, salt_datum, info_datum;
|
||||||
|
gpointer alloc = NULL;
|
||||||
|
gpointer buffer = NULL;
|
||||||
|
guint hash_len;
|
||||||
|
gsize i;
|
||||||
|
int ret;
|
||||||
|
gboolean result = TRUE;
|
||||||
|
|
||||||
|
for (i = 0; hash_algos[i].name; i++) {
|
||||||
|
if (g_str_equal (hash_algos[i].name, hash_algo)) {
|
||||||
|
algo = hash_algos[i].algo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_return_val_if_fail (algo != GNUTLS_MAC_UNKNOWN, FALSE);
|
||||||
|
|
||||||
|
hash_len = gnutls_hmac_get_len (algo);
|
||||||
|
g_return_val_if_fail (hash_len != 0, FALSE);
|
||||||
|
g_return_val_if_fail (n_output <= 255 * hash_len, FALSE);
|
||||||
|
|
||||||
|
/* Buffer we need to for intermediate stuff */
|
||||||
|
buffer = egg_secure_alloc (hash_len);
|
||||||
|
g_return_val_if_fail (buffer, FALSE);
|
||||||
|
|
||||||
|
/* Salt defaults to hash_len zeros */
|
||||||
|
if (!salt) {
|
||||||
|
alloc = g_malloc0 (hash_len);
|
||||||
|
if (!alloc) {
|
||||||
|
result = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
salt = alloc;
|
||||||
|
n_salt = hash_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 1: Extract */
|
||||||
|
input_datum.data = (void *)input;
|
||||||
|
input_datum.size = n_input;
|
||||||
|
salt_datum.data = (void *)salt;
|
||||||
|
salt_datum.size = n_salt;
|
||||||
|
|
||||||
|
ret = gnutls_hkdf_extract (algo, &input_datum, &salt_datum, buffer);
|
||||||
|
if (ret < 0) {
|
||||||
|
result = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 2: Expand */
|
||||||
|
input_datum.data = buffer;
|
||||||
|
input_datum.size = hash_len;
|
||||||
|
info_datum.data = (void *)info;
|
||||||
|
info_datum.size = n_info;
|
||||||
|
|
||||||
|
ret = gnutls_hkdf_expand (algo, &input_datum, &info_datum,
|
||||||
|
output, n_output);
|
||||||
|
if (ret < 0) {
|
||||||
|
result = FALSE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free (alloc);
|
||||||
|
egg_secure_free (buffer);
|
||||||
|
return result;
|
||||||
|
}
|
@ -13,10 +13,9 @@
|
|||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received copies of the GNU General Public License and
|
||||||
* License along with this program; if not, write to the Free Software
|
* the GNU Lesser General Public License along with this program. If
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
* not, see http://www.gnu.org/licenses/.
|
||||||
* MA 02110-1301 USA
|
|
||||||
*
|
*
|
||||||
* Author: Stef Walter <stefw@collabora.co.uk>
|
* Author: Stef Walter <stefw@collabora.co.uk>
|
||||||
*/
|
*/
|
||||||
@ -24,10 +23,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "egg-hkdf.h"
|
#include "egg-hkdf.h"
|
||||||
#include "egg-secure-memory.h"
|
|
||||||
|
|
||||||
#include <gcrypt.h>
|
#include <gcrypt.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
gboolean
|
gboolean
|
156
egg/egg-keyring1-gnutls.c
Normal file
156
egg/egg-keyring1-gnutls.c
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/* 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;
|
||||||
|
}
|
193
egg/egg-keyring1-libgcrypt.c
Normal file
193
egg/egg-keyring1-libgcrypt.c
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
/* 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 <gcrypt.h>
|
||||||
|
|
||||||
|
#define PBKDF2_HASH_ALGO GCRY_MD_SHA256
|
||||||
|
#define MAC_ALGO GCRY_MAC_HMAC_SHA256
|
||||||
|
#define CIPHER_ALGO GCRY_CIPHER_AES128
|
||||||
|
|
||||||
|
void
|
||||||
|
egg_keyring1_create_nonce (guint8 *nonce,
|
||||||
|
gsize nonce_size)
|
||||||
|
{
|
||||||
|
gcry_create_nonce (nonce, nonce_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
egg_keyring1_derive_key (const gchar *password,
|
||||||
|
gsize n_password,
|
||||||
|
GBytes *salt,
|
||||||
|
guint32 iteration_count)
|
||||||
|
{
|
||||||
|
guint8 *buffer;
|
||||||
|
gcry_error_t gcry;
|
||||||
|
|
||||||
|
buffer = egg_secure_alloc (KEY_SIZE);
|
||||||
|
g_return_val_if_fail (buffer, NULL);
|
||||||
|
|
||||||
|
gcry = gcry_kdf_derive (password,
|
||||||
|
n_password,
|
||||||
|
GCRY_KDF_PBKDF2, PBKDF2_HASH_ALGO,
|
||||||
|
g_bytes_get_data (salt, NULL),
|
||||||
|
g_bytes_get_size (salt),
|
||||||
|
iteration_count,
|
||||||
|
KEY_SIZE, buffer);
|
||||||
|
if (gcry != 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)
|
||||||
|
{
|
||||||
|
gcry_mac_hd_t hd;
|
||||||
|
gcry_error_t gcry;
|
||||||
|
gconstpointer secret;
|
||||||
|
gsize n_secret;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
gcry = gcry_mac_open (&hd, MAC_ALGO, 0, NULL);
|
||||||
|
g_return_val_if_fail (gcry == 0, FALSE);
|
||||||
|
|
||||||
|
secret = g_bytes_get_data (key, &n_secret);
|
||||||
|
gcry = gcry_mac_setkey (hd, secret, n_secret);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
gcry = gcry_mac_write (hd, value, n_value);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
n_value = MAC_SIZE;
|
||||||
|
gcry = gcry_mac_read (hd, buffer, &n_value);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (n_value != MAC_SIZE)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
gcry_mac_close (hd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
gcry_cipher_hd_t hd;
|
||||||
|
gcry_error_t gcry;
|
||||||
|
gconstpointer secret;
|
||||||
|
gsize n_secret;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
gcry = gcry_cipher_open (&hd, CIPHER_ALGO, GCRY_CIPHER_MODE_CBC, 0);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
secret = g_bytes_get_data (key, &n_secret);
|
||||||
|
gcry = gcry_cipher_setkey (hd, secret, n_secret);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
gcry = gcry_cipher_setiv (hd, data + n_data, IV_SIZE);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
gcry = gcry_cipher_decrypt (hd, data, n_data, NULL, 0);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
gcry_cipher_close (hd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
egg_keyring1_encrypt (GBytes *key,
|
||||||
|
guint8 *data,
|
||||||
|
gsize n_data)
|
||||||
|
{
|
||||||
|
gcry_cipher_hd_t hd;
|
||||||
|
gcry_error_t gcry;
|
||||||
|
gconstpointer secret;
|
||||||
|
gsize n_secret;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
gcry = gcry_cipher_open (&hd, CIPHER_ALGO, GCRY_CIPHER_MODE_CBC, 0);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
secret = g_bytes_get_data (key, &n_secret);
|
||||||
|
gcry = gcry_cipher_setkey (hd, secret, n_secret);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
egg_keyring1_create_nonce (data + n_data, IV_SIZE);
|
||||||
|
|
||||||
|
gcry = gcry_cipher_setiv (hd, data + n_data, IV_SIZE);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
gcry = gcry_cipher_encrypt (hd, data, n_data, NULL, 0);
|
||||||
|
if (gcry != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
gcry_cipher_close (hd);
|
||||||
|
return ret;
|
||||||
|
}
|
55
egg/egg-keyring1.h
Normal file
55
egg/egg-keyring1.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EGG_KEYRING1_H_
|
||||||
|
#define EGG_KEYRING1_H_
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#define SALT_SIZE 32
|
||||||
|
#define ITERATION_COUNT 100000
|
||||||
|
|
||||||
|
#define MAC_SIZE 32
|
||||||
|
|
||||||
|
#define CIPHER_BLOCK_SIZE 16
|
||||||
|
#define KEY_SIZE 16
|
||||||
|
#define IV_SIZE CIPHER_BLOCK_SIZE
|
||||||
|
|
||||||
|
void egg_keyring1_create_nonce (guint8 *nonce,
|
||||||
|
gsize nonce_size);
|
||||||
|
|
||||||
|
GBytes *egg_keyring1_derive_key (const char *password,
|
||||||
|
gsize n_password,
|
||||||
|
GBytes *salt,
|
||||||
|
guint32 iteration_count);
|
||||||
|
|
||||||
|
gboolean egg_keyring1_calculate_mac (GBytes *key,
|
||||||
|
const guint8 *value,
|
||||||
|
gsize n_value,
|
||||||
|
guint8 *buffer);
|
||||||
|
|
||||||
|
gboolean egg_keyring1_verify_mac (GBytes *key,
|
||||||
|
const guint8 *value,
|
||||||
|
gsize n_value,
|
||||||
|
const guint8 *data);
|
||||||
|
|
||||||
|
gboolean egg_keyring1_decrypt (GBytes *key,
|
||||||
|
guint8 *data,
|
||||||
|
gsize n_data);
|
||||||
|
|
||||||
|
gboolean egg_keyring1_encrypt (GBytes *key,
|
||||||
|
guint8 *data,
|
||||||
|
gsize n_data);
|
||||||
|
|
||||||
|
#endif /* EGG_KEYRING1_H_ */
|
@ -8,14 +8,27 @@ libegg_deps = [
|
|||||||
glib_deps,
|
glib_deps,
|
||||||
]
|
]
|
||||||
|
|
||||||
if get_option('gcrypt')
|
if with_crypto
|
||||||
libegg_sources += [
|
libegg_sources += [
|
||||||
'egg-dh.c',
|
'egg-dh.c',
|
||||||
'egg-hkdf.c',
|
|
||||||
'egg-libgcrypt.c',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
libegg_deps += gcrypt_dep
|
if with_gcrypt
|
||||||
|
libegg_sources += [
|
||||||
|
'egg-dh-libgcrypt.c',
|
||||||
|
'egg-hkdf-libgcrypt.c',
|
||||||
|
'egg-keyring1-libgcrypt.c',
|
||||||
|
'egg-libgcrypt.c',
|
||||||
|
]
|
||||||
|
elif with_gnutls
|
||||||
|
libegg_sources += [
|
||||||
|
'egg-dh-gnutls.c',
|
||||||
|
'egg-hkdf-gnutls.c',
|
||||||
|
'egg-keyring1-gnutls.c',
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
|
||||||
|
libegg_deps += crypto_deps
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('tpm2')
|
if get_option('tpm2')
|
||||||
@ -38,7 +51,7 @@ test_names = [
|
|||||||
'test-secmem',
|
'test-secmem',
|
||||||
]
|
]
|
||||||
|
|
||||||
if get_option('gcrypt')
|
if with_crypto
|
||||||
test_names += [
|
test_names += [
|
||||||
'test-dh',
|
'test-dh',
|
||||||
'test-hkdf',
|
'test-hkdf',
|
||||||
|
@ -33,86 +33,81 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gcrypt.h>
|
|
||||||
|
|
||||||
EGG_SECURE_DEFINE_GLIB_GLOBALS ();
|
EGG_SECURE_DEFINE_GLIB_GLOBALS ();
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_perform (void)
|
test_perform (void)
|
||||||
{
|
{
|
||||||
gcry_mpi_t p, g;
|
egg_dh_params *params;
|
||||||
gcry_mpi_t x1, X1;
|
egg_dh_pubkey *y1;
|
||||||
gcry_mpi_t x2, X2;
|
egg_dh_privkey *x1;
|
||||||
gpointer k1, k2;
|
egg_dh_pubkey *y2;
|
||||||
|
egg_dh_privkey *x2;
|
||||||
|
GBytes *k1, *k2;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
gsize n1, n2;
|
|
||||||
|
|
||||||
/* Load up the parameters */
|
/* Load up the parameters */
|
||||||
if (!egg_dh_default_params ("ietf-ike-grp-modp-768", &p, &g))
|
params = egg_dh_default_params ("ietf-ike-grp-modp-768");
|
||||||
|
if (!params)
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
|
||||||
/* Generate secrets */
|
/* Generate secrets */
|
||||||
ret = egg_dh_gen_pair (p, g, 0, &X1, &x1);
|
ret = egg_dh_gen_pair (params, 0, &y1, &x1);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
ret = egg_dh_gen_pair (p, g, 0, &X2, &x2);
|
ret = egg_dh_gen_pair (params, 0, &y2, &x2);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
|
|
||||||
/* Calculate keys */
|
/* Calculate keys */
|
||||||
k1 = egg_dh_gen_secret (X2, x1, p, &n1);
|
k1 = egg_dh_gen_secret (y1, x2, params);
|
||||||
g_assert_nonnull (k1);
|
g_assert_nonnull (k1);
|
||||||
k2 = egg_dh_gen_secret (X1, x2, p, &n2);
|
k2 = egg_dh_gen_secret (y2, x1, params);
|
||||||
g_assert_nonnull (k2);
|
g_assert_nonnull (k2);
|
||||||
|
|
||||||
/* Keys must be the same */
|
/* Keys must be the same */
|
||||||
egg_assert_cmpsize (n1, ==, n2);
|
g_assert_cmpmem (g_bytes_get_data (k1, NULL), g_bytes_get_size (k1),
|
||||||
g_assert_true (memcmp (k1, k2, n1) == 0);
|
g_bytes_get_data (k2, NULL), g_bytes_get_size (k2));
|
||||||
|
|
||||||
gcry_mpi_release (p);
|
egg_dh_params_free (params);
|
||||||
gcry_mpi_release (g);
|
egg_dh_pubkey_free (y1);
|
||||||
gcry_mpi_release (x1);
|
egg_dh_privkey_free (x1);
|
||||||
gcry_mpi_release (X1);
|
|
||||||
egg_secure_free (k1);
|
egg_secure_free (k1);
|
||||||
gcry_mpi_release (x2);
|
egg_dh_pubkey_free (y2);
|
||||||
gcry_mpi_release (X2);
|
egg_dh_privkey_free (x2);
|
||||||
egg_secure_free (k2);
|
egg_secure_free (k2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_short_pair (void)
|
test_short_pair (void)
|
||||||
{
|
{
|
||||||
gcry_mpi_t p, g;
|
egg_dh_params *params;
|
||||||
gcry_mpi_t x1, X1;
|
egg_dh_pubkey *y1;
|
||||||
|
egg_dh_privkey *x1;
|
||||||
|
GBytes *bytes;
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
|
|
||||||
/* Load up the parameters */
|
/* Load up the parameters */
|
||||||
ret = egg_dh_default_params ("ietf-ike-grp-modp-1024", &p, &g);
|
params = egg_dh_default_params ("ietf-ike-grp-modp-1024");
|
||||||
g_assert_true (ret);
|
g_assert_nonnull (params);
|
||||||
g_assert_cmpuint (gcry_mpi_get_nbits (p), ==, 1024);
|
|
||||||
|
|
||||||
/* Generate secrets */
|
/* Generate secrets */
|
||||||
ret = egg_dh_gen_pair (p, g, 512, &X1, &x1);
|
ret = egg_dh_gen_pair (params, 512, &y1, &x1);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
g_assert_cmpuint (gcry_mpi_get_nbits (x1), <=, 512);
|
bytes = egg_dh_pubkey_export (y1);
|
||||||
|
g_assert_cmpuint (g_bytes_get_size (bytes), <=, 512);
|
||||||
|
g_bytes_unref (bytes);
|
||||||
|
|
||||||
gcry_mpi_release (p);
|
egg_dh_params_free (params);
|
||||||
gcry_mpi_release (g);
|
egg_dh_pubkey_free (y1);
|
||||||
gcry_mpi_release (x1);
|
egg_dh_privkey_free (x1);
|
||||||
gcry_mpi_release (X1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_dh_default (const gchar *name, guint bits)
|
check_dh_default (const gchar *name, guint bits)
|
||||||
{
|
{
|
||||||
gboolean ret;
|
gboolean ret;
|
||||||
gcry_mpi_t p, g, check;
|
|
||||||
gconstpointer prime, base;
|
gconstpointer prime, base;
|
||||||
gsize n_prime, n_base;
|
gsize n_prime, n_base;
|
||||||
gcry_error_t gcry;
|
|
||||||
|
|
||||||
ret = egg_dh_default_params (name, &p, &g);
|
|
||||||
g_assert_true (ret);
|
|
||||||
g_assert_cmpint (gcry_mpi_get_nbits (p), ==, bits);
|
|
||||||
g_assert_cmpint (gcry_mpi_get_nbits (g), <, gcry_mpi_get_nbits (p));
|
|
||||||
|
|
||||||
ret = egg_dh_default_params_raw (name, &prime, &n_prime, &base, &n_base);
|
ret = egg_dh_default_params_raw (name, &prime, &n_prime, &base, &n_base);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
@ -120,19 +115,6 @@ check_dh_default (const gchar *name, guint bits)
|
|||||||
egg_assert_cmpsize (n_prime, >, 0);
|
egg_assert_cmpsize (n_prime, >, 0);
|
||||||
g_assert_nonnull (base);
|
g_assert_nonnull (base);
|
||||||
egg_assert_cmpsize (n_base, >, 0);
|
egg_assert_cmpsize (n_base, >, 0);
|
||||||
|
|
||||||
gcry = gcry_mpi_scan (&check, GCRYMPI_FMT_USG, prime, n_prime, NULL);
|
|
||||||
g_assert_true (gcry == 0);
|
|
||||||
g_assert_true (gcry_mpi_cmp (check, p) == 0);
|
|
||||||
gcry_mpi_release (check);
|
|
||||||
|
|
||||||
gcry = gcry_mpi_scan (&check, GCRYMPI_FMT_USG, base, n_base, NULL);
|
|
||||||
g_assert_true (gcry == 0);
|
|
||||||
g_assert_true (gcry_mpi_cmp (check, g) == 0);
|
|
||||||
gcry_mpi_release (check);
|
|
||||||
|
|
||||||
gcry_mpi_release (p);
|
|
||||||
gcry_mpi_release (g);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -180,11 +162,10 @@ test_default_8192 (void)
|
|||||||
static void
|
static void
|
||||||
test_default_bad (void)
|
test_default_bad (void)
|
||||||
{
|
{
|
||||||
gboolean ret;
|
egg_dh_params *params;
|
||||||
gcry_mpi_t p, g;
|
|
||||||
|
|
||||||
ret = egg_dh_default_params ("bad-name", &p, &g);
|
params = egg_dh_default_params ("bad-name");
|
||||||
g_assert_false (ret);
|
g_assert_null (params);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -36,7 +36,7 @@ libsecret_headers = [
|
|||||||
'secret-value.h',
|
'secret-value.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
if get_option('gcrypt')
|
if with_crypto
|
||||||
libsecret_sources += [
|
libsecret_sources += [
|
||||||
'secret-file-backend.c',
|
'secret-file-backend.c',
|
||||||
'secret-file-collection.c',
|
'secret-file-collection.c',
|
||||||
@ -76,8 +76,8 @@ libsecret_dependencies = [
|
|||||||
glib_deps,
|
glib_deps,
|
||||||
]
|
]
|
||||||
|
|
||||||
if get_option('gcrypt')
|
if with_crypto
|
||||||
libsecret_dependencies += gcrypt_dep
|
libsecret_dependencies += crypto_deps
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libsecret_cflags = [
|
libsecret_cflags = [
|
||||||
@ -231,7 +231,7 @@ test_names = [
|
|||||||
'test-collection',
|
'test-collection',
|
||||||
]
|
]
|
||||||
|
|
||||||
if get_option('gcrypt')
|
if with_crypto
|
||||||
test_names += [
|
test_names += [
|
||||||
'test-file-collection',
|
'test-file-collection',
|
||||||
]
|
]
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "secret-backend.h"
|
#include "secret-backend.h"
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
#include "secret-file-backend.h"
|
#include "secret-file-backend.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -148,11 +148,11 @@ backend_get_impl_type (void)
|
|||||||
GIOExtensionPoint *ep;
|
GIOExtensionPoint *ep;
|
||||||
|
|
||||||
g_type_ensure (secret_service_get_type ());
|
g_type_ensure (secret_service_get_type ());
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
g_type_ensure (secret_file_backend_get_type ());
|
g_type_ensure (secret_file_backend_get_type ());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
if ((g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS) || g_getenv ("SNAP_NAME") != NULL) &&
|
if ((g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS) || g_getenv ("SNAP_NAME") != NULL) &&
|
||||||
_secret_file_backend_check_portal_version ())
|
_secret_file_backend_check_portal_version ())
|
||||||
extension_name = "file";
|
extension_name = "file";
|
||||||
|
@ -16,26 +16,15 @@
|
|||||||
|
|
||||||
#include "secret-file-collection.h"
|
#include "secret-file-collection.h"
|
||||||
|
|
||||||
#include "egg/egg-libgcrypt.h"
|
#include "egg/egg-keyring1.h"
|
||||||
#include "egg/egg-secure-memory.h"
|
#include "egg/egg-secure-memory.h"
|
||||||
|
|
||||||
EGG_SECURE_DECLARE (secret_file_collection);
|
EGG_SECURE_DECLARE (secret_file_collection);
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_GCRYPT
|
||||||
#include <gcrypt.h>
|
#include "egg/egg-libgcrypt.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PBKDF2_HASH_ALGO GCRY_MD_SHA256
|
|
||||||
#define SALT_SIZE 32
|
|
||||||
#define ITERATION_COUNT 100000
|
|
||||||
|
|
||||||
#define MAC_ALGO GCRY_MAC_HMAC_SHA256
|
|
||||||
#define MAC_SIZE 32
|
|
||||||
|
|
||||||
#define CIPHER_ALGO GCRY_CIPHER_AES256
|
|
||||||
#define CIPHER_BLOCK_SIZE 16
|
|
||||||
#define IV_SIZE CIPHER_BLOCK_SIZE
|
|
||||||
|
|
||||||
#define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n"
|
#define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n"
|
||||||
#define KEYRING_FILE_HEADER_LEN 16
|
#define KEYRING_FILE_HEADER_LEN 16
|
||||||
|
|
||||||
@ -85,158 +74,6 @@ get_file_last_modified (SecretFileCollection *self)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_derive_key (SecretFileCollection *self)
|
|
||||||
{
|
|
||||||
const gchar *password;
|
|
||||||
gsize n_password;
|
|
||||||
gchar *key;
|
|
||||||
gsize n_salt;
|
|
||||||
gcry_error_t gcry;
|
|
||||||
|
|
||||||
password = secret_value_get (self->password, &n_password);
|
|
||||||
|
|
||||||
key = egg_secure_alloc (CIPHER_BLOCK_SIZE);
|
|
||||||
self->key = g_bytes_new_with_free_func (key,
|
|
||||||
CIPHER_BLOCK_SIZE,
|
|
||||||
egg_secure_free,
|
|
||||||
key);
|
|
||||||
|
|
||||||
n_salt = g_bytes_get_size (self->salt);
|
|
||||||
gcry = gcry_kdf_derive (password, n_password,
|
|
||||||
GCRY_KDF_PBKDF2, PBKDF2_HASH_ALGO,
|
|
||||||
g_bytes_get_data (self->salt, NULL), n_salt,
|
|
||||||
self->iteration_count, CIPHER_BLOCK_SIZE, key);
|
|
||||||
return (gcry != 0) ? FALSE : TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_calculate_mac (SecretFileCollection *self,
|
|
||||||
const guint8 *value, gsize n_value,
|
|
||||||
guint8 *buffer)
|
|
||||||
{
|
|
||||||
gcry_mac_hd_t hd;
|
|
||||||
gcry_error_t gcry;
|
|
||||||
gconstpointer secret;
|
|
||||||
gsize n_secret;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
|
|
||||||
gcry = gcry_mac_open (&hd, MAC_ALGO, 0, NULL);
|
|
||||||
g_return_val_if_fail (gcry == 0, FALSE);
|
|
||||||
|
|
||||||
secret = g_bytes_get_data (self->key, &n_secret);
|
|
||||||
gcry = gcry_mac_setkey (hd, secret, n_secret);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
gcry = gcry_mac_write (hd, value, n_value);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
n_value = MAC_SIZE;
|
|
||||||
gcry = gcry_mac_read (hd, buffer, &n_value);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (n_value != MAC_SIZE)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
gcry_mac_close (hd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_verify_mac (SecretFileCollection *self,
|
|
||||||
const guint8 *value, gsize n_value,
|
|
||||||
const guint8 *data)
|
|
||||||
{
|
|
||||||
guint8 buffer[MAC_SIZE];
|
|
||||||
guint8 status = 0;
|
|
||||||
gsize i;
|
|
||||||
|
|
||||||
if (!do_calculate_mac (self, value, n_value, buffer)) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < MAC_SIZE; i++) {
|
|
||||||
status |= data[i] ^ buffer[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return status == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_decrypt (SecretFileCollection *self,
|
|
||||||
guint8 *data,
|
|
||||||
gsize n_data)
|
|
||||||
{
|
|
||||||
gcry_cipher_hd_t hd;
|
|
||||||
gcry_error_t gcry;
|
|
||||||
gconstpointer secret;
|
|
||||||
gsize n_secret;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
|
|
||||||
gcry = gcry_cipher_open (&hd, CIPHER_ALGO, GCRY_CIPHER_MODE_CBC, 0);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
secret = g_bytes_get_data (self->key, &n_secret);
|
|
||||||
gcry = gcry_cipher_setkey (hd, secret, n_secret);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
gcry = gcry_cipher_setiv (hd, data + n_data, IV_SIZE);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
gcry = gcry_cipher_decrypt (hd, data, n_data, NULL, 0);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
(void) gcry_cipher_close (hd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_encrypt (SecretFileCollection *self,
|
|
||||||
guint8 *data,
|
|
||||||
gsize n_data)
|
|
||||||
{
|
|
||||||
gcry_cipher_hd_t hd;
|
|
||||||
gcry_error_t gcry;
|
|
||||||
gconstpointer secret;
|
|
||||||
gsize n_secret;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
|
|
||||||
gcry = gcry_cipher_open (&hd, CIPHER_ALGO, GCRY_CIPHER_MODE_CBC, 0);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
secret = g_bytes_get_data (self->key, &n_secret);
|
|
||||||
gcry = gcry_cipher_setkey (hd, secret, n_secret);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
gcry_create_nonce (data + n_data, IV_SIZE);
|
|
||||||
|
|
||||||
gcry = gcry_cipher_setiv (hd, data + n_data, IV_SIZE);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
gcry = gcry_cipher_encrypt (hd, data, n_data, NULL, 0);
|
|
||||||
if (gcry != 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
(void) gcry_cipher_close (hd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
secret_file_collection_init (SecretFileCollection *self)
|
secret_file_collection_init (SecretFileCollection *self)
|
||||||
{
|
{
|
||||||
@ -309,8 +146,9 @@ secret_file_collection_class_init (SecretFileCollectionClass *klass)
|
|||||||
g_param_spec_boxed ("password", "password", "Password",
|
g_param_spec_boxed ("password", "password", "Password",
|
||||||
SECRET_TYPE_VALUE,
|
SECRET_TYPE_VALUE,
|
||||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
|
||||||
|
#ifdef WITH_GCRYPT
|
||||||
egg_libgcrypt_initialize ();
|
egg_libgcrypt_initialize ();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -328,6 +166,8 @@ load_contents (SecretFileCollection *self,
|
|||||||
guint64 usage_count;
|
guint64 usage_count;
|
||||||
gconstpointer data;
|
gconstpointer data;
|
||||||
gsize n_data;
|
gsize n_data;
|
||||||
|
const gchar *password;
|
||||||
|
gsize n_password;
|
||||||
|
|
||||||
p = contents;
|
p = contents;
|
||||||
if (length < KEYRING_FILE_HEADER_LEN ||
|
if (length < KEYRING_FILE_HEADER_LEN ||
|
||||||
@ -379,7 +219,12 @@ load_contents (SecretFileCollection *self,
|
|||||||
g_variant_unref (salt_array);
|
g_variant_unref (salt_array);
|
||||||
g_variant_unref (variant);
|
g_variant_unref (variant);
|
||||||
|
|
||||||
if (!do_derive_key (self)) {
|
password = secret_value_get (self->password, &n_password);
|
||||||
|
self->key = egg_keyring1_derive_key (password,
|
||||||
|
n_password,
|
||||||
|
self->salt,
|
||||||
|
self->iteration_count);
|
||||||
|
if (!self->key) {
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
SECRET_ERROR,
|
SECRET_ERROR,
|
||||||
SECRET_ERROR_PROTOCOL,
|
SECRET_ERROR_PROTOCOL,
|
||||||
@ -395,15 +240,22 @@ init_empty_file (SecretFileCollection *self,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GVariantBuilder builder;
|
GVariantBuilder builder;
|
||||||
|
const gchar *password;
|
||||||
|
gsize n_password;
|
||||||
guint8 salt[SALT_SIZE];
|
guint8 salt[SALT_SIZE];
|
||||||
|
|
||||||
gcry_create_nonce (salt, sizeof(salt));
|
egg_keyring1_create_nonce (salt, sizeof(salt));
|
||||||
self->salt = g_bytes_new (salt, sizeof(salt));
|
self->salt = g_bytes_new (salt, sizeof(salt));
|
||||||
self->iteration_count = ITERATION_COUNT;
|
self->iteration_count = ITERATION_COUNT;
|
||||||
self->modified = g_date_time_new_now_utc ();
|
self->modified = g_date_time_new_now_utc ();
|
||||||
self->usage_count = 0;
|
self->usage_count = 0;
|
||||||
|
|
||||||
if (!do_derive_key (self)) {
|
password = secret_value_get (self->password, &n_password);
|
||||||
|
self->key = egg_keyring1_derive_key (password,
|
||||||
|
n_password,
|
||||||
|
self->salt,
|
||||||
|
self->iteration_count);
|
||||||
|
if (!self->key) {
|
||||||
g_set_error_literal (error,
|
g_set_error_literal (error,
|
||||||
SECRET_ERROR,
|
SECRET_ERROR,
|
||||||
SECRET_ERROR_PROTOCOL,
|
SECRET_ERROR_PROTOCOL,
|
||||||
@ -555,7 +407,10 @@ hash_attributes (SecretFileCollection *self,
|
|||||||
GVariant *variant;
|
GVariant *variant;
|
||||||
|
|
||||||
value = g_hash_table_lookup (attributes, l->data);
|
value = g_hash_table_lookup (attributes, l->data);
|
||||||
if (!do_calculate_mac (self, (guint8 *)value, strlen (value), buffer)) {
|
if (!egg_keyring1_calculate_mac (self->key,
|
||||||
|
(const guint8 *)value,
|
||||||
|
strlen (value),
|
||||||
|
buffer)) {
|
||||||
g_list_free (keys);
|
g_list_free (keys);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -597,7 +452,7 @@ hashed_attributes_match (SecretFileCollection *self,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!do_verify_mac (self, value, strlen ((char *)value), data)) {
|
if (!egg_keyring1_verify_mac (self->key, value, strlen ((char *)value), data)) {
|
||||||
g_variant_unref (hashed_attribute);
|
g_variant_unref (hashed_attribute);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -693,7 +548,7 @@ secret_file_collection_replace (SecretFileCollection *self,
|
|||||||
g_variant_store (serialized_item, data);
|
g_variant_store (serialized_item, data);
|
||||||
g_variant_unref (serialized_item);
|
g_variant_unref (serialized_item);
|
||||||
memset (data + n_data, n_padded - n_data, n_padded - n_data);
|
memset (data + n_data, n_padded - n_data, n_padded - n_data);
|
||||||
if (!do_encrypt (self, data, n_padded)) {
|
if (!egg_keyring1_encrypt (self->key, data, n_padded)) {
|
||||||
egg_secure_free (data);
|
egg_secure_free (data);
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
SECRET_ERROR,
|
SECRET_ERROR,
|
||||||
@ -702,7 +557,7 @@ secret_file_collection_replace (SecretFileCollection *self,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!do_calculate_mac (self, data, n_padded + IV_SIZE,
|
if (!egg_keyring1_calculate_mac (self->key, data, n_padded + IV_SIZE,
|
||||||
data + n_padded + IV_SIZE)) {
|
data + n_padded + IV_SIZE)) {
|
||||||
egg_secure_free (data);
|
egg_secure_free (data);
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
@ -791,7 +646,7 @@ _secret_file_item_decrypt (GVariant *encrypted,
|
|||||||
}
|
}
|
||||||
|
|
||||||
n_padded -= MAC_SIZE;
|
n_padded -= MAC_SIZE;
|
||||||
if (!do_verify_mac (collection, data, n_padded, data + n_padded)) {
|
if (!egg_keyring1_verify_mac (collection->key, data, n_padded, data + n_padded)) {
|
||||||
egg_secure_free (data);
|
egg_secure_free (data);
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
SECRET_ERROR,
|
SECRET_ERROR,
|
||||||
@ -801,7 +656,7 @@ _secret_file_item_decrypt (GVariant *encrypted,
|
|||||||
}
|
}
|
||||||
|
|
||||||
n_padded -= IV_SIZE;
|
n_padded -= IV_SIZE;
|
||||||
if (!do_decrypt (collection, data, n_padded)) {
|
if (!egg_keyring1_decrypt (collection->key, data, n_padded)) {
|
||||||
egg_secure_free (data);
|
egg_secure_free (data);
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
SECRET_ERROR,
|
SECRET_ERROR,
|
||||||
|
@ -17,10 +17,18 @@
|
|||||||
|
|
||||||
#include "secret-private.h"
|
#include "secret-private.h"
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
#include "egg/egg-dh.h"
|
#include "egg/egg-dh.h"
|
||||||
#include "egg/egg-hkdf.h"
|
#include "egg/egg-hkdf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_GCRYPT
|
||||||
#include "egg/egg-libgcrypt.h"
|
#include "egg/egg-libgcrypt.h"
|
||||||
|
#include <gcrypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_GNUTLS
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "egg/egg-hex.h"
|
#include "egg/egg-hex.h"
|
||||||
@ -36,10 +44,10 @@ EGG_SECURE_DECLARE (secret_session);
|
|||||||
struct _SecretSession {
|
struct _SecretSession {
|
||||||
gchar *path;
|
gchar *path;
|
||||||
const gchar *algorithms;
|
const gchar *algorithms;
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
gcry_mpi_t prime;
|
egg_dh_params *params;
|
||||||
gcry_mpi_t privat;
|
egg_dh_privkey *privat;
|
||||||
gcry_mpi_t publi;
|
egg_dh_pubkey *publi;
|
||||||
#endif
|
#endif
|
||||||
gpointer key;
|
gpointer key;
|
||||||
gsize n_key;
|
gsize n_key;
|
||||||
@ -54,55 +62,52 @@ _secret_session_free (gpointer data)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
g_free (session->path);
|
g_free (session->path);
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
gcry_mpi_release (session->publi);
|
egg_dh_pubkey_free (session->publi);
|
||||||
gcry_mpi_release (session->privat);
|
egg_dh_privkey_free (session->privat);
|
||||||
gcry_mpi_release (session->prime);
|
egg_dh_params_free (session->params);
|
||||||
#endif
|
#endif
|
||||||
egg_secure_free (session->key);
|
egg_secure_free (session->key);
|
||||||
g_free (session);
|
g_free (session);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
|
|
||||||
static GVariant *
|
static GVariant *
|
||||||
request_open_session_aes (SecretSession *session)
|
request_open_session_aes (SecretSession *session)
|
||||||
{
|
{
|
||||||
gcry_error_t gcry;
|
GBytes *buffer;
|
||||||
gcry_mpi_t base;
|
|
||||||
unsigned char *buffer;
|
|
||||||
size_t n_buffer;
|
|
||||||
GVariant *argument;
|
GVariant *argument;
|
||||||
|
|
||||||
g_assert (session->prime == NULL);
|
g_assert (session->params == NULL);
|
||||||
g_assert (session->privat == NULL);
|
g_assert (session->privat == NULL);
|
||||||
g_assert (session->publi == NULL);
|
g_assert (session->publi == NULL);
|
||||||
|
|
||||||
|
#ifdef WITH_GCRYPT
|
||||||
egg_libgcrypt_initialize ();
|
egg_libgcrypt_initialize ();
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Initialize our local parameters and values */
|
/* Initialize our local parameters and values */
|
||||||
if (!egg_dh_default_params ("ietf-ike-grp-modp-1024",
|
session->params = egg_dh_default_params ("ietf-ike-grp-modp-1024");
|
||||||
&session->prime, &base))
|
if (!session->params)
|
||||||
g_return_val_if_reached (NULL);
|
g_return_val_if_reached (NULL);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
g_printerr ("\n lib prime: ");
|
g_printerr ("\n lib params: ");
|
||||||
gcry_mpi_dump (session->prime);
|
egg_dh_params_dump (session->params);
|
||||||
g_printerr ("\n lib base: ");
|
|
||||||
gcry_mpi_dump (base);
|
|
||||||
g_printerr ("\n");
|
g_printerr ("\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!egg_dh_gen_pair (session->prime, base, 0,
|
if (!egg_dh_gen_pair (session->params, 0,
|
||||||
&session->publi, &session->privat))
|
&session->publi, &session->privat))
|
||||||
g_return_val_if_reached (NULL);
|
g_return_val_if_reached (NULL);
|
||||||
gcry_mpi_release (base);
|
|
||||||
|
|
||||||
gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, session->publi);
|
buffer = egg_dh_pubkey_export (session->publi);
|
||||||
g_return_val_if_fail (gcry == 0, NULL);
|
g_return_val_if_fail (buffer != NULL, NULL);
|
||||||
argument = g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
|
argument = g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"),
|
||||||
buffer, n_buffer, TRUE,
|
buffer,
|
||||||
gcry_free, buffer);
|
TRUE);
|
||||||
|
g_bytes_unref (buffer);
|
||||||
|
|
||||||
return g_variant_new ("(sv)", ALGORITHMS_AES, argument);
|
return g_variant_new ("(sv)", ALGORITHMS_AES, argument);
|
||||||
}
|
}
|
||||||
@ -111,14 +116,11 @@ static gboolean
|
|||||||
response_open_session_aes (SecretSession *session,
|
response_open_session_aes (SecretSession *session,
|
||||||
GVariant *response)
|
GVariant *response)
|
||||||
{
|
{
|
||||||
gconstpointer buffer;
|
GBytes *buffer;
|
||||||
GVariant *argument;
|
GVariant *argument;
|
||||||
const gchar *sig;
|
const gchar *sig;
|
||||||
gsize n_buffer;
|
egg_dh_pubkey *peer;
|
||||||
gcry_mpi_t peer;
|
GBytes *ikm;
|
||||||
gcry_error_t gcry;
|
|
||||||
gpointer ikm;
|
|
||||||
gsize n_ikm;
|
|
||||||
|
|
||||||
sig = g_variant_get_type_string (response);
|
sig = g_variant_get_type_string (response);
|
||||||
g_return_val_if_fail (sig != NULL, FALSE);
|
g_return_val_if_fail (sig != NULL, FALSE);
|
||||||
@ -131,24 +133,27 @@ response_open_session_aes (SecretSession *session,
|
|||||||
g_assert (session->path == NULL);
|
g_assert (session->path == NULL);
|
||||||
g_variant_get (response, "(vo)", &argument, &session->path);
|
g_variant_get (response, "(vo)", &argument, &session->path);
|
||||||
|
|
||||||
buffer = g_variant_get_fixed_array (argument, &n_buffer, sizeof (guchar));
|
buffer = g_variant_get_data_as_bytes (argument);
|
||||||
gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL);
|
peer = egg_dh_pubkey_new_from_bytes (session->params, buffer);
|
||||||
g_return_val_if_fail (gcry == 0, FALSE);
|
g_bytes_unref (buffer);
|
||||||
|
g_return_val_if_fail (peer != NULL, FALSE);
|
||||||
g_variant_unref (argument);
|
g_variant_unref (argument);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
g_printerr (" lib publi: ");
|
g_printerr (" lib publi: ");
|
||||||
gcry_mpi_dump (session->publi);
|
egg_dh_pubkey_dump (session->publi);
|
||||||
g_printerr ("\n lib peer: ");
|
g_printerr ("\n lib peer: ");
|
||||||
gcry_mpi_dump (peer);
|
egg_dh_pubkey_dump (peer);
|
||||||
g_printerr ("\n");
|
g_printerr ("\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ikm = egg_dh_gen_secret (peer, session->privat, session->prime, &n_ikm);
|
ikm = egg_dh_gen_secret (peer, session->privat, session->params);
|
||||||
gcry_mpi_release (peer);
|
egg_dh_pubkey_free (peer);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
g_printerr (" lib ikm: %s\n", egg_hex_encode (ikm, n_ikm));
|
g_printerr (" lib ikm: %s\n",
|
||||||
|
egg_hex_encode (g_bytes_get_data (ikm, NULL),
|
||||||
|
g_bytes_get_size (ikm)));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ikm == NULL) {
|
if (ikm == NULL) {
|
||||||
@ -160,16 +165,19 @@ response_open_session_aes (SecretSession *session,
|
|||||||
|
|
||||||
session->n_key = 16;
|
session->n_key = 16;
|
||||||
session->key = egg_secure_alloc (session->n_key);
|
session->key = egg_secure_alloc (session->n_key);
|
||||||
if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0,
|
if (!egg_hkdf_perform ("sha256",
|
||||||
|
g_bytes_get_data (ikm, NULL),
|
||||||
|
g_bytes_get_size (ikm),
|
||||||
|
NULL, 0, NULL, 0,
|
||||||
session->key, session->n_key))
|
session->key, session->n_key))
|
||||||
g_return_val_if_reached (FALSE);
|
g_return_val_if_reached (FALSE);
|
||||||
egg_secure_free (ikm);
|
g_bytes_unref (ikm);
|
||||||
|
|
||||||
session->algorithms = ALGORITHMS_AES;
|
session->algorithms = ALGORITHMS_AES;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_GCRYPT */
|
#endif /* WITH_CRYPTO */
|
||||||
|
|
||||||
static GVariant *
|
static GVariant *
|
||||||
request_open_session_plain (SecretSession *session)
|
request_open_session_plain (SecretSession *session)
|
||||||
@ -252,7 +260,7 @@ on_service_open_session_plain (GObject *source,
|
|||||||
g_object_unref (task);
|
g_object_unref (task);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_service_open_session_aes (GObject *source,
|
on_service_open_session_aes (GObject *source,
|
||||||
@ -301,7 +309,7 @@ on_service_open_session_aes (GObject *source,
|
|||||||
g_object_unref (task);
|
g_object_unref (task);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_GCRYPT */
|
#endif /* WITH_CRYPTO */
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -320,7 +328,7 @@ _secret_session_open (SecretService *service,
|
|||||||
g_task_set_task_data (task, closure, open_session_closure_free);
|
g_task_set_task_data (task, closure, open_session_closure_free);
|
||||||
|
|
||||||
g_dbus_proxy_call (G_DBUS_PROXY (service), "OpenSession",
|
g_dbus_proxy_call (G_DBUS_PROXY (service), "OpenSession",
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
request_open_session_aes (closure->session),
|
request_open_session_aes (closure->session),
|
||||||
G_DBUS_CALL_FLAGS_NONE, -1,
|
G_DBUS_CALL_FLAGS_NONE, -1,
|
||||||
cancellable, on_service_open_session_aes,
|
cancellable, on_service_open_session_aes,
|
||||||
@ -346,7 +354,7 @@ _secret_session_open_finish (GAsyncResult *result,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
pkcs7_unpad_bytes_in_place (guchar *padded,
|
pkcs7_unpad_bytes_in_place (guchar *padded,
|
||||||
@ -378,6 +386,8 @@ pkcs7_unpad_bytes_in_place (guchar *padded,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_GCRYPT
|
||||||
|
|
||||||
static SecretValue *
|
static SecretValue *
|
||||||
service_decode_aes_secret (SecretSession *session,
|
service_decode_aes_secret (SecretSession *session,
|
||||||
gconstpointer param,
|
gconstpointer param,
|
||||||
@ -448,6 +458,85 @@ service_decode_aes_secret (SecretSession *session,
|
|||||||
|
|
||||||
#endif /* WITH_GCRYPT */
|
#endif /* WITH_GCRYPT */
|
||||||
|
|
||||||
|
#ifdef WITH_GNUTLS
|
||||||
|
|
||||||
|
static SecretValue *
|
||||||
|
service_decode_aes_secret (SecretSession *session,
|
||||||
|
gconstpointer param,
|
||||||
|
gsize n_param,
|
||||||
|
gconstpointer value,
|
||||||
|
gsize n_value,
|
||||||
|
const gchar *content_type)
|
||||||
|
{
|
||||||
|
gnutls_cipher_hd_t cih;
|
||||||
|
gnutls_datum_t iv, key;
|
||||||
|
gsize n_padded;
|
||||||
|
int ret;
|
||||||
|
guchar *padded;
|
||||||
|
|
||||||
|
if (n_param != 16) {
|
||||||
|
g_info ("received an encrypted secret structure with invalid parameter");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n_value == 0 || n_value % 16 != 0) {
|
||||||
|
g_info ("received an encrypted secret structure with bad secret length");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_printerr (" lib iv: %s\n", egg_hex_encode (param, n_param));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_printerr (" lib key: %s\n", egg_hex_encode (session->key, session->n_key));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
iv.data = (void *)param;
|
||||||
|
iv.size = n_param;
|
||||||
|
key.data = session->key;
|
||||||
|
key.size = session->n_key;
|
||||||
|
ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
|
||||||
|
if (ret != 0) {
|
||||||
|
g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the memory buffer */
|
||||||
|
n_padded = n_value;
|
||||||
|
padded = egg_secure_alloc (n_padded);
|
||||||
|
if (!padded) {
|
||||||
|
gnutls_cipher_deinit (cih);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy (padded, value, n_padded);
|
||||||
|
|
||||||
|
/* Perform the decryption */
|
||||||
|
ret = gnutls_cipher_decrypt2 (cih, padded, n_padded, padded, n_padded);
|
||||||
|
if (ret < 0) {
|
||||||
|
egg_secure_clear (padded, n_padded);
|
||||||
|
egg_secure_free (padded);
|
||||||
|
gnutls_cipher_deinit (cih);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnutls_cipher_deinit (cih);
|
||||||
|
|
||||||
|
/* Unpad the resulting value */
|
||||||
|
if (!pkcs7_unpad_bytes_in_place (padded, &n_padded)) {
|
||||||
|
egg_secure_clear (padded, n_padded);
|
||||||
|
egg_secure_free (padded);
|
||||||
|
g_info ("received an invalid or unencryptable secret");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return secret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WITH_GNUTLS */
|
||||||
|
|
||||||
|
#endif /* WITH_CRYPTO */
|
||||||
|
|
||||||
static SecretValue *
|
static SecretValue *
|
||||||
service_decode_plain_secret (SecretSession *session,
|
service_decode_plain_secret (SecretSession *session,
|
||||||
gconstpointer param,
|
gconstpointer param,
|
||||||
@ -497,7 +586,7 @@ _secret_session_decode_secret (SecretSession *session,
|
|||||||
value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar));
|
value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar));
|
||||||
g_variant_get_child (encoded, 3, "s", &content_type);
|
g_variant_get_child (encoded, 3, "s", &content_type);
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
if (session->key != NULL)
|
if (session->key != NULL)
|
||||||
result = service_decode_aes_secret (session, param, n_param,
|
result = service_decode_aes_secret (session, param, n_param,
|
||||||
value, n_value, content_type);
|
value, n_value, content_type);
|
||||||
@ -514,7 +603,7 @@ _secret_session_decode_secret (SecretSession *session,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
|
|
||||||
static guchar*
|
static guchar*
|
||||||
pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
|
pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
|
||||||
@ -536,6 +625,8 @@ pkcs7_pad_bytes_in_secure_memory (gconstpointer secret,
|
|||||||
return padded;
|
return padded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_GCRYPT
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
service_encode_aes_secret (SecretSession *session,
|
service_encode_aes_secret (SecretSession *session,
|
||||||
SecretValue *value,
|
SecretValue *value,
|
||||||
@ -595,6 +686,72 @@ service_encode_aes_secret (SecretSession *session,
|
|||||||
|
|
||||||
#endif /* WITH_GCRYPT */
|
#endif /* WITH_GCRYPT */
|
||||||
|
|
||||||
|
#ifdef WITH_GNUTLS
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
service_encode_aes_secret (SecretSession *session,
|
||||||
|
SecretValue *value,
|
||||||
|
GVariantBuilder *builder)
|
||||||
|
{
|
||||||
|
gnutls_cipher_hd_t cih = NULL;
|
||||||
|
guchar *padded;
|
||||||
|
gsize n_padded;
|
||||||
|
int ret;
|
||||||
|
gnutls_datum_t iv, key;
|
||||||
|
gpointer iv_data;
|
||||||
|
gconstpointer secret;
|
||||||
|
gsize n_secret;
|
||||||
|
GVariant *child;
|
||||||
|
|
||||||
|
g_variant_builder_add (builder, "o", session->path);
|
||||||
|
|
||||||
|
secret = secret_value_get (value, &n_secret);
|
||||||
|
|
||||||
|
/* Perform the encoding here */
|
||||||
|
padded = pkcs7_pad_bytes_in_secure_memory (secret, n_secret, &n_padded);
|
||||||
|
g_assert (padded != NULL);
|
||||||
|
|
||||||
|
/* Setup the IV */
|
||||||
|
iv_data = g_malloc0 (16);
|
||||||
|
iv.data = iv_data;
|
||||||
|
iv.size = 16;
|
||||||
|
ret = gnutls_rnd (GNUTLS_RND_NONCE, iv.data, iv.size);
|
||||||
|
g_return_val_if_fail (ret >= 0, FALSE);
|
||||||
|
|
||||||
|
/* Setup the key */
|
||||||
|
key.data = session->key;
|
||||||
|
key.size = session->n_key;
|
||||||
|
|
||||||
|
/* Create the cipher */
|
||||||
|
ret = gnutls_cipher_init (&cih, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
|
||||||
|
if (ret < 0) {
|
||||||
|
g_warning ("couldn't create AES cipher: %s", gnutls_strerror (ret));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the encryption */
|
||||||
|
ret = gnutls_cipher_encrypt2 (cih, padded, n_padded, padded, n_padded);
|
||||||
|
if (ret < 0) {
|
||||||
|
gnutls_cipher_deinit (cih);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnutls_cipher_deinit (cih);
|
||||||
|
|
||||||
|
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), iv_data, 16, TRUE, g_free, iv_data);
|
||||||
|
g_variant_builder_add_value (builder, child);
|
||||||
|
|
||||||
|
child = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), padded, n_padded, TRUE, egg_secure_free, padded);
|
||||||
|
g_variant_builder_add_value (builder, child);
|
||||||
|
|
||||||
|
g_variant_builder_add (builder, "s", secret_value_get_content_type (value));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WITH_GNUTLS */
|
||||||
|
|
||||||
|
#endif /* WITH_CRYPTO */
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
service_encode_plain_secret (SecretSession *session,
|
service_encode_plain_secret (SecretSession *session,
|
||||||
SecretValue *value,
|
SecretValue *value,
|
||||||
@ -634,7 +791,7 @@ _secret_session_encode_secret (SecretSession *session,
|
|||||||
type = g_variant_type_new ("(oayays)");
|
type = g_variant_type_new ("(oayays)");
|
||||||
builder = g_variant_builder_new (type);
|
builder = g_variant_builder_new (type);
|
||||||
|
|
||||||
#ifdef WITH_GCRYPT
|
#ifdef WITH_CRYPTO
|
||||||
if (session->key)
|
if (session->key)
|
||||||
ret = service_encode_aes_secret (session, value, builder);
|
ret = service_encode_aes_secret (session, value, builder);
|
||||||
else
|
else
|
||||||
|
@ -29,6 +29,12 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef WITH_CRYPTO
|
||||||
|
#define SESSION_ALGO "dh-ietf1024-sha256-aes128-cbc-pkcs7"
|
||||||
|
#else
|
||||||
|
#define SESSION_ALGO "plain"
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SecretService *service;
|
SecretService *service;
|
||||||
} Test;
|
} Test;
|
||||||
@ -73,7 +79,7 @@ test_ensure (Test *test,
|
|||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL);
|
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL);
|
||||||
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "dh-ietf1024-sha256-aes128-cbc-pkcs7");
|
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -91,14 +97,14 @@ test_ensure_twice (Test *test,
|
|||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL);
|
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL);
|
||||||
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "dh-ietf1024-sha256-aes128-cbc-pkcs7");
|
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO);
|
||||||
|
|
||||||
path = g_strdup (secret_service_get_session_dbus_path (test->service));
|
path = g_strdup (secret_service_get_session_dbus_path (test->service));
|
||||||
ret = secret_service_ensure_session_sync (test->service, NULL, &error);
|
ret = secret_service_ensure_session_sync (test->service, NULL, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), ==, path);
|
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), ==, path);
|
||||||
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "dh-ietf1024-sha256-aes128-cbc-pkcs7");
|
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO);
|
||||||
|
|
||||||
g_free (path);
|
g_free (path);
|
||||||
}
|
}
|
||||||
@ -172,7 +178,7 @@ test_ensure_async_aes (Test *test,
|
|||||||
|
|
||||||
g_assert_true (ret);
|
g_assert_true (ret);
|
||||||
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL);
|
g_assert_cmpstr (secret_service_get_session_dbus_path (test->service), !=, NULL);
|
||||||
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, "dh-ietf1024-sha256-aes128-cbc-pkcs7");
|
g_assert_cmpstr (secret_service_get_session_algorithms (test->service), ==, SESSION_ALGO);
|
||||||
|
|
||||||
g_object_unref (result);
|
g_object_unref (result);
|
||||||
}
|
}
|
||||||
|
40
meson.build
40
meson.build
@ -30,11 +30,37 @@ glib_deps = [
|
|||||||
dependency('gio-unix-2.0', version: '>=' + min_glib_version),
|
dependency('gio-unix-2.0', version: '>=' + min_glib_version),
|
||||||
]
|
]
|
||||||
|
|
||||||
min_libgcrypt_version = '1.2.2'
|
with_gcrypt = false
|
||||||
gcrypt_dep = dependency('libgcrypt',
|
with_gnutls = false
|
||||||
|
with_crypto = false
|
||||||
|
|
||||||
|
crypto_deps = []
|
||||||
|
|
||||||
|
if get_option('crypto') == 'libgcrypt'
|
||||||
|
min_libgcrypt_version = '1.2.2'
|
||||||
|
gcrypt_dep = dependency(
|
||||||
|
'libgcrypt',
|
||||||
version: '>=' + min_libgcrypt_version,
|
version: '>=' + min_libgcrypt_version,
|
||||||
required: get_option('gcrypt'),
|
required: false,
|
||||||
)
|
)
|
||||||
|
if gcrypt_dep.found()
|
||||||
|
with_gcrypt = true
|
||||||
|
with_crypto = true
|
||||||
|
crypto_deps += gcrypt_dep
|
||||||
|
endif
|
||||||
|
elif get_option('crypto') == 'gnutls'
|
||||||
|
min_gnutls_version = '3.8.2'
|
||||||
|
gnutls_dep = dependency(
|
||||||
|
'gnutls',
|
||||||
|
version: '>=' + min_gnutls_version,
|
||||||
|
required: false,
|
||||||
|
)
|
||||||
|
if gnutls_dep.found()
|
||||||
|
with_gnutls = true
|
||||||
|
with_crypto = true
|
||||||
|
crypto_deps += gnutls_dep
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
min_tss2_version = '3.0.3'
|
min_tss2_version = '3.0.3'
|
||||||
tss2_esys = dependency('tss2-esys', version: '>=' + min_tss2_version, required: get_option('tpm2'))
|
tss2_esys = dependency('tss2-esys', version: '>=' + min_tss2_version, required: get_option('tpm2'))
|
||||||
@ -58,9 +84,11 @@ conf.set_quoted('LOCALEDIR', libsecret_prefix / get_option('localedir'))
|
|||||||
conf.set_quoted('PACKAGE_NAME', meson.project_name())
|
conf.set_quoted('PACKAGE_NAME', meson.project_name())
|
||||||
conf.set_quoted('PACKAGE_STRING', meson.project_name())
|
conf.set_quoted('PACKAGE_STRING', meson.project_name())
|
||||||
conf.set_quoted('PACKAGE_VERSION', meson.project_version())
|
conf.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||||
conf.set('WITH_GCRYPT', get_option('gcrypt'))
|
conf.set('WITH_GCRYPT', with_gcrypt)
|
||||||
|
conf.set('WITH_GNUTLS', with_gnutls)
|
||||||
|
conf.set('WITH_CRYPTO', with_crypto)
|
||||||
conf.set('WITH_TPM', get_option('tpm2'))
|
conf.set('WITH_TPM', get_option('tpm2'))
|
||||||
if get_option('gcrypt')
|
if with_gcrypt
|
||||||
conf.set_quoted('LIBGCRYPT_VERSION', min_libgcrypt_version)
|
conf.set_quoted('LIBGCRYPT_VERSION', min_libgcrypt_version)
|
||||||
endif
|
endif
|
||||||
if get_option('tpm2')
|
if get_option('tpm2')
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
option('manpage', type: 'boolean', value: true, description: 'Build man pages')
|
option('manpage', type: 'boolean', value: true, description: 'Build man pages')
|
||||||
option('gcrypt', type: 'boolean', value: true, description: 'With gcrypt and transport encryption')
|
option('crypto', type: 'combo', choices: ['libgcrypt', 'gnutls', 'disabled'], value: 'libgcrypt', description: 'Backend library to implement transport encryption')
|
||||||
option('debugging', type: 'boolean', value: false, description: 'Turn debugging on/off')
|
option('debugging', type: 'boolean', value: false, description: 'Turn debugging on/off')
|
||||||
option('vapi', type: 'boolean', value: true, description: 'Create VAPI file.')
|
option('vapi', type: 'boolean', value: true, description: 'Create VAPI file.')
|
||||||
option('gtk_doc', type: 'boolean', value: true, description: 'Build reference documentation using gi-docgen')
|
option('gtk_doc', type: 'boolean', value: true, description: 'Build reference documentation using gi-docgen')
|
||||||
|
@ -10,7 +10,7 @@ secret_tool = executable('secret-tool',
|
|||||||
install: true,
|
install: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
if get_option('gcrypt') and host_machine.system() != 'windows'
|
if with_crypto and host_machine.system() != 'windows'
|
||||||
test('test-secret-tool.sh',
|
test('test-secret-tool.sh',
|
||||||
find_program('test-secret-tool.sh'),
|
find_program('test-secret-tool.sh'),
|
||||||
env: test_env,
|
env: test_env,
|
||||||
|
Loading…
Reference in New Issue
Block a user