Browse Source

Merge branch 'develop'

master gfsecret-0.3.0
Damien Goutte-Gattat 5 years ago
parent
commit
d75ca49876
  1. 2
      AUTHORS
  2. 6
      NEWS
  3. 113
      README.md
  4. 22
      configure.ac
  5. 2
      man/Makefile.am
  6. 136
      man/gfsec-split.1.in
  7. 12
      man/gfsec-use.1.in
  8. 16
      src/Makefile.am
  9. 31
      src/gfsec-errors.h
  10. 225
      src/gfsec-split.c
  11. 181
      src/gfsec-use.c
  12. 228
      src/mtp-support.c
  13. 68
      src/scheme-file.c
  14. 50
      src/scheme-file.h
  15. 199
      src/scheme-gio.c
  16. 32
      src/scheme-gio.h
  17. 420
      src/scheme-libmtp.c
  18. 49
      src/scheme-libmtp.h
  19. 183
      src/scheme-module.c
  20. 61
      src/scheme-module.h
  21. 29
      src/schemes.h
  22. 666
      src/secret.c
  23. 146
      src/secret.h
  24. 374
      src/secretcfg.c
  25. 20
      src/secretcfg.h
  26. 60
      src/share.c
  27. 75
      src/util.c
  28. 5
      src/util.h

2
AUTHORS

@ -1 +1 @@
Damien Goutte-Gattat
Damien Goutte-Gattat <dgouttegattat@incenp.org>

6
NEWS

@ -1,3 +1,9 @@
Changes in gfsecret 0.3.0
* Improve error messages.
* Add the gfsec-split program.
Changes in gfsecret 0.2.0
* Check share data against SHA-256 hash.

113
README.md

@ -2,36 +2,118 @@ Gfsecret - Secret sharing tools
===============================
Gfsecret is a set of tools to facilitate secret sharing according to the
Adi Shamir’s secret sharing scheme.
[Adi Shamir’s secret sharing
scheme](http://dl.acm.org/citation.cfm?id=359176).
Two tools are provided: _gfsec-split_ will split a file into several
shares, and _gfsec-use_ will reconstruct the original file from some of
the shares.
Share URIs
----------
Both tools use the concept of a _share URI_, which is a way of
describing a share with a URI-like syntax. The _gfsec-split_ program
uses them to know where to dispatch the generated shares, and
_gfsec-use_ uses them to know where to search for shares in order to
reconstruct the original file.
A share URI has the following form:
scheme://authority/path?parameters
The _scheme_ part indicates the method to use to access the share, and
can be `file` (to access a share on the local filesystem), `label` (to
access a share on an external volume identified by its label), `uuid`
(to access a share on an external volume identified by its UUID), or
`mtp` (to access a share on a MTP-compliant device identified by its
serial number).
The `authority` part identifies the storage device. It's the volume's
label when using the `label://` scheme, its UUID when using the
`uuid://` scheme, and the device's serial number when using the `mtp://`
scheme. In the `file://` scheme, that part should be empty.
The _path_ part is the pathname to the share file on the device.
Finally, the _parameters_ part, which is optional, may specify options
as `key=value` pairs. Currently, valid options are `sha256`, which
specifies a SHA2-256 hash that the share should match, and `share=no`,
which indicates that the corresponding share is not actually a share but
contains the whole secret.
gfsec-split
-----------
The _gfsec-split_ program allows to split a file into _M_ shares,
dispatch them at distinct locations (including external storage
devices), then delete the original file.
The program takes the path to the file to split as its single positional
argument. Use the `-s` option to specify a share to create using the URI
syntax described above (use one `-s` option for each share).
Consider the following example:
gfsec-split -n 2 \
-s file:///home/alice/.local/share/gfsecret/mysecret \
-s label://USBSTICK/mysecret \
-s mtp://RF2GB6X704P/Documents/mysecret \
/home/alice/mysecret
This will split the file `/home/alice/mysecret` into three shares: one
in Alice's home directory on the local filesystem, one on a USB storage
device with the label `USBSTICK`, and one on a MTP-compliant device with
the serial number `RF2GB6X704P`. Two shares will be needed to
reconstruct the original file, which means in this case that one of the
two removable devices will have to be present.
Note that the shares need not to have the same basename than the
original file.
Once the file is splitted, _gfsec-split_ will delete the original file
(unless you used the `-k` option), and will create a configuration file
in `$XDG_CONFIG_HOME/gfsecret/mysecret` (or at any location specified by
the `-c` option) which could later be used by _gfsec-use_.
If you move the shares around after they have been generated, you should
take care of updating that configuration file, otherwise _gfsec-use_
will be unable to fetch the shares.
As a convenience, before splitting you may call _gfsec-split_ with the
single `-l` option to list the available external volumes and their
identifiers.
gfsec-use
---------
The gfsec-use program allows to temporarily reconstruct a splitted file
from shares that have been dispersed on several external devices (USB
sticks and/or MTP-compliant devices like some smartphones or audio
players).
The _gfsec-use_ program allows to temporarily reconstruct a splitted
file from shares that have been dispersed on several external devices.
The program needs a configuration file (by default,
`$XDG_CONFIG_HOME/gfsecret/default.conf`) which describes the shared
secret. Here is a sample configuration:
secret. If the original file has been splitted using the _gfsec-split_
program, the configuration file will have been automatically generated.
For example, here is the configuration file that could have been
generated by the example above:
OUTFILE=/home/alice/mysecret
MINSHARES=2
URI=file:///home/alice/.local/share/gfsecret/mysecret.024
URI=label://MYSTICK/mysecretfile.070
URI=label://MYSTICK/mysecret.070
URI=mtp://RF2GB6X704P/Documents/mysecret.139
With such a configuration, gfse-use will attempt to reconstruct the file
`/home/alice/mysecret`, using at least two of the three available
With such a configuration, _gfse-use_ will attempt to reconstruct the
file `/home/alice/mysecret`, using at least two of the three available
shares: one available on the local filesystem, one on a USB storage
device with the label `MYSTICK`, and one on a MTP-compliant device with
the serial number `RF2GB6X704P`. Gfsec-use will automatically detect
the serial number `RF2GB6X704P`. _Gfsec-use_ will automatically detect
which devices are currently connected and will fetch from them the
corresponding shares.
Once the secret file has been reconstructed (if enough shares are
available), gfsec-use will spawn a new shell (or any other program
available), _gfsec-use_ will spawn a new shell (or any other program
specified on its command line). When the shell (or the user-specified
command) terminates, the reconstructed secret file will be automatically
deleted.
@ -44,7 +126,7 @@ Gfsecret depends on the following libraries at compile-time:
- [libgfshare](http://www.digital-scurf.org/software/libgfshare), which
implements the secret sharing scheme proper (mandatory);
- [libgcrypt](http://www.gnupg.org/), for the SHA-256 implementation
(mandatory);
and random number generation (mandatory);
- [GIO](http://developer.gnome.org/gio/), to access shares stored on
external volumes (typically USB storage) (optional);
- [libmtp](http://libmtp.sourceforge.net/), to access shares stored on
@ -58,12 +140,9 @@ License, version 3 or higher. The full license is included in the
[COPYING file](COPYING) of the source distribution.
Homepage and contact
--------------------
Homepage and repository
-----------------------
The project is located at http://www.incenp.org/dvlpt/gfsecret.html.
The latest source code is available in a Git repository at
git://git.incenp.org/gfsecret.git and may also be browsed at
http://www.incenp.org/gitweb/?p=gfsecret.git;a=summary.
The author may be contacted at the following address:
Damien Goutte-Gattat <dgouttegattat@incenp.org>

22
configure.ac

@ -1,6 +1,6 @@
dnl Configure template for the gfsecret package
AC_INIT([gfsecret], [0.2.0],
AC_INIT([gfsecret], [0.3.0],
[dgouttegattat@incenp.org])
AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_MACRO_DIR([m4])
@ -37,9 +37,25 @@ PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.22],
[AC_DEFINE([HAVE_GIO], [1], [Define if gio-2.0 is present.])],
[])
dnl Set max size for secret
AC_ARG_ENABLE([max-size],
[AS_HELP_STRING([--enable-max-size],
[Limit size of secret file @<:@default=no@:>@])],
[],
[enable_max_size=no])
AS_CASE([$enable_max_size],
[yes], [max_secret_size=16777216],
[no], [max_secret_size=0],
[max_secret_size=$enable_max_size])
AS_IF([test $max_secret_size -eq 0],
[max_secret_size_string="Unlimited"],
[max_secret_size_string="$max_secret_size bytes"])
AC_DEFINE_UNQUOTED([GFSEC_SECRET_MAX_SIZE], [$max_secret_size],
[Max size of secret.])
dnl Output files
AC_CONFIG_FILES([Makefile lib/Makefile src/Makefile
man/Makefile man/gfsec-use.1])
man/Makefile man/gfsec-use.1 man/gfsec-split.1])
AC_OUTPUT
dnl Summary
@ -49,4 +65,6 @@ Configuration complete
Prefix: '${prefix}'
Compiler: '${CC} ${CFLAGS} ${CPPFLAGS}'
Secret max size: ${max_secret_size_string}
"

2
man/Makefile.am

@ -1 +1 @@
man_MANS = gfsec-use.1
man_MANS = gfsec-use.1 gfsec-split.1

136
man/gfsec-split.1.in

@ -0,0 +1,136 @@
.TH GFSEC-SPLIT 08/30/2015 "gfsecret @PACKAGE_VERSION@"
.SH NAME
gfsec-split \- Split a file into shares and dispatch them
.SH SYNOPSIS
.SY gfsec-split
.RB [ \-h | --help ]
.RB [ \-v | --version ]
.RB [ \-n | --threshold
.IR N ]
.RB [ \-s | --share
.IR URI ]
.RB [ \-c | --config
.IR file ]
.RB [ \-k | --keep ]
.RB [ \-l | --list-supports ]
.B file
.YS
.SH DESCRIPTION
.PP
.B gfsec-split
splits a file into a number of shares and dispatches
the resulting shares onto external storage supports.
.PP
The splitted file can then be temporarily reconstructed
using the accompanying program
.BR gfsec-use (1).
.SH OPTIONS
.TP
.BR -h ", " --help
Display the help message.
.TP
.BR -v ", " --version
Display the version message.
.TP
.BR -n ", " --threshold " " \fiN\fR
Specify the minimal number of shares required to
re-assemble the splitted file. Default is 2.
.TP
.BR -s ", " --share " " \fiURI\fR
Specify the location of a share. See below for the
format of the
.I URI
parameter. Repeat this option for all of the shares
to be generated.
.TP
.BR -c ", " --config " " \fiFILE\fR
Write the configuration file (allowing to reconstruct
the secret with
.BR gfsec-use (1)
) to the specified file. Default is the basename of
the splitted file in $XDG_CONFIG_HOME/gfsecret.
.TP
.BR -k ", " --keep
By default,
.B gfsec-split
will delete the original file once it has been
successfully splitted. Use this option to prevent
the file to be deleted.
.TP
.BR -l ", " --list-supports
List all the currently available supports which can
be used to store shares, then quit.
.SH SHARE URIs
.PP
Shares are described using a URI-like syntax. For each share,
the URI indicates a storage device and a pathname on that device.
.PP
Supported URI schemes are:
.TP
file:///
Indicates a file on the local filesystem.
.TP
uuid://\fIuuid\fR/
Indicates a file on the external volume identified
by the specified UUID.
.TP
label://\fIlabel\fR/
Indicates a file on the external volume identified
by the specified label.
.TP
mtp://\fIserial\fR/
Indicates a file on the MTP device identified by the
specified serial number.
.SH EXAMPLE INVOCATION
.PP
.nf
gfsec-split \\
-s file:///home/alice/.local/share/gfsecret/mysecret \\
-s label://USBSTICK/mysecret \\
-s mtp://RF2GB6X704P/Documents/mysecret \\
/home/alice/mysecret
.fi
.PP
The above example will split the file
.I /home/alice/mysecret
into three shares: one on the local filesystem, one on the
USB mass storage device with the label \fIUSBSTICK\fR, and
one on the MTP-compliant device with the serial \fIRF2GB6X704P\fR.
A configuration file will be written in
.I $XDG_CONFIG_HOME/gfsecret/mysecret
allowing to automatically reconstruct the file with
.BR gfsec-use (1)
provided at least one of the two removable supports are
present.
.SH REPORTING BUGS
.PP
Report bugs to
.MT @PACKAGE_BUGREPORT@
Damien Goutte-Gattat
.ME .
.SH SEE ALSO
.BR gfsec-use (1),
.BR gfsplit (1),
.BR gfcombine (1),
.BR libgfshare (3),
.BR gfshare (7)
.SH COPYRIGHT
.ad l
.PP
Copyright \(co 2016 Damien Goutte-Gattat
.PP
This program is released under the GNU General Public License.
See the COPYING file in the source distribution or
.UR http://www.gnu.org/licenses/gpl.html
.UE .

12
man/gfsec-use.1.in

@ -19,7 +19,9 @@ gfsec-use \- Make use of a shared secret
.B gfsec-use
reconstructs a secret file that has been previously
splitted using a tool like
.BR gfsplit (1).
.BR gfsplit (1)
or the accompanying program
.BR gfsec-split (1).
.PP
A user-specified command (or a shell) is spawn once
the secret has been reconstructed, and the secret
@ -100,6 +102,13 @@ expected SHA-256 hash value of the share data. If such a
parameter is specified, a share will only be used if the
data matches the expected hash value.
.PP
The
.BR gfsec-split (1)
program, used to split a file into shares, will automatically
generate a suitable configuration file allowing to reconstruct
the original file.
.SH EXAMPLE CONFIGURATION FILE
.PP
.nf
@ -118,6 +127,7 @@ Damien Goutte-Gattat
.ME .
.SH SEE ALSO
.BR gfsec-split (1),
.BR gfsplit (1),
.BR gfcombine (1),
.BR libgfshare (3),

16
src/Makefile.am

@ -1,9 +1,15 @@
bin_PROGRAMS = gfsec-use
bin_PROGRAMS = gfsec-use gfsec-split
gfsec_use_SOURCES = gfsec-use.c util.c util.h share.c share.h \
secretcfg.c secretcfg.h \
mtp-support.c mtp-support.h \
uuid-support.c uuid-support.h
common_sources = util.c util.h secret.c secret.h \
secretcfg.c secretcfg.h gfsec-errors.h \
schemes.h scheme-module.c scheme-module.h \
scheme-libmtp.c scheme-libmtp.h \
scheme-gio.c scheme-gio.h \
scheme-file.c scheme-file.h
gfsec_use_SOURCES = gfsec-use.c $(common_sources)
gfsec_split_SOURCES = gfsec-split.c $(common_sources)
AM_CPPFLAGS = -I$(top_srcdir)/lib $(LIBGFSHARE_CFLAGS) $(LIBMTP_CFLAGS) $(GIO_CFLAGS)
AM_LDFLAGS = -L$(top_builddir)/lib $(LIBGFSHARE_LIBS) $(LIBMTP_LIBS) $(GIO_LIBS)

31
src/gfsec-errors.h

@ -0,0 +1,31 @@
/*
* gfsecret - Secret sharing tools
* Copyright (C) 2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
GFSEC_ERROR(SUCCESS, 0, "Success")
GFSEC_ERROR(SYSTEM_ERROR, -1, strerror(errno))
GFSEC_ERROR(INVALID_CALL, -2, "A function was improperly called")
GFSEC_ERROR(NOT_ENOUGH_SHARES, -3, "Not enough shares available to reconstitute the secret")
GFSEC_ERROR(TOO_MANY_SHARES, -4, "Too many shares")
GFSEC_ERROR(SHARE_NOT_AVAILABLE, -5, "A share is not available")
GFSEC_ERROR(INVALID_LENGTH, -6, "Shares have inconsistent lengths")
GFSEC_ERROR(INVALID_SHARE, -7, "Checksum failed for share data")
GFSEC_ERROR(CONFIG_LINE_TOO_LONG, -9, "Line too long")
GFSEC_ERROR(CONFIG_INVALID_URI, -10, "Invalid share URI")
GFSEC_ERROR(CONFIG_INVALID_HASH, -11, "Invalid hash value")
GFSEC_ERROR(CONFIG_UNKNOWN_SCHEME, -12, "Unknown URI scheme")
GFSEC_ERROR(CONFIG_INVALID_THRESHOLD, -13, "Invalid threshold")

225
src/gfsec-split.c

@ -0,0 +1,225 @@
/*
* gfsecret - Secret sharing tools
* Copyright (C) 2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <err.h>
#include <gcrypt.h>
#include "util.h"
#include "secretcfg.h"
#include "scheme-module.h"
static void
usage(int status)
{
puts("Usage: gfsec-split [options] file\n\
Split the specified file for later use with gfsec-use.\n");
puts("Options:\n\
-h, --help Display this help message.\n\
-v, --version Display the version message.\n");
puts("\
-n, --threshold N Specify the minimal number of shares\n\
required to re-assemble the secret.\n\
Default is 2.\n\
-s, --share URI Add a share.\n");
puts("\
-c, --config FILE Write configuration to the specified\n\
file. Default is the basename of the\n\
splitted file in gfsecret's configuration\n\
directory.\n");
puts("\
-k, --keep Do not delete the original file.\n");
puts("\
-l, --list-supports List available supports and exit.\n");
printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
exit(status);
}
static void
info(void)
{
printf("\
gfsec-split (%s %s)\n\
Copyright (C) 2016 Damien Goutte-Gattat\n\
\n\
This program is released under the GNU General Public License.\n\
See the COPYING file or <http://www.gnu.org/licenses/gpl.html>.\n\
", PACKAGE_NAME, VERSION);
exit(EXIT_SUCCESS);
}
static unsigned
get_uinteger_or_die(const char *arg)
{
unsigned val;
char *endptr;
errno = 0;
val = strtoul(arg, &endptr, 10);
if ( errno != 0 || endptr == arg )
errx(EXIT_FAILURE, "Invalid argument, unsigned integer expected: %s", arg);
return val;
}
int
main(int argc, char **argv)
{
int c, list_mode;
unsigned threshold, keep_original;
char *output_base, *config_path;
gfsec_secret_t *cfg;
struct option options[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'v' },
{ "treshold", 1, NULL, 'n' },
{ "share", 1, NULL, 's' },
{ "config", 1, NULL, 'c' },
{ "keep", 0, NULL, 'k' },
{ "list-supports", 0, NULL, 'l' },
{ NULL, 0, NULL, 0 }
};
setprogname(argv[0]);
threshold = 2;
keep_original = list_mode = 0;
output_base = config_path = NULL;
srandom(time(NULL));
if ( ! (cfg = gfsec_secret_new()) )
err(EXIT_FAILURE, "Cannot create secret");
while ( (c = getopt_long(argc, argv, "hvn:s:c:kl",
options, NULL)) != -1 ) {
switch ( c ) {
case 'h':
usage(EXIT_SUCCESS);
break;
case '?':
usage(EXIT_FAILURE);
break;
case 'v':
info();
break;
case 'n':
threshold = get_uinteger_or_die(optarg);
break;
case 's':
if ( (c = gfsec_parse_uri(optarg, cfg, 1)) != 0 )
errx(EXIT_FAILURE, "Cannot add share: %s", gfsec_error_string(c));
break;
case 'c':
config_path = optarg;
break;
case 'k':
keep_original = 1;
break;
case 'l':
list_mode = 1;
break;
}
}
gfsec_scheme_module_init();
if ( list_mode ) {
gfsec_scheme_module_list_authorities(stdout);
exit(EXIT_SUCCESS);
}
if ( ! gcry_check_version(GCRYPT_VERSION) )
errx(EXIT_FAILURE, "libgcrypt version mismatch");
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
if ( optind >= argc )
errx(EXIT_FAILURE, "Missing secret file");
if ( ! output_base && ! (output_base = get_file_basename(argv[optind])) )
err(EXIT_FAILURE, "No output basename");
if ( ! config_path ) {
char *base;
if ( ! (base = get_file_basename(argv[optind])) )
err(EXIT_FAILURE, "Cannot get basename");
if ( asprintf(&config_path, "%s/gfsecret/%s.conf",
getenv("XDG_CONFIG_HOME"), base) == -1 )
err(EXIT_FAILURE, "Cannot construct a pathname for the configuration file");
free(base);
}
if ( (c = gfsec_secret_set_secret_file(cfg, argv[optind])) != 0 )
errx(EXIT_FAILURE, "Cannot set secret: %s", gfsec_error_string(c));
if ( (c = gfsec_secret_split(cfg, threshold)) != 0 )
errx(EXIT_FAILURE, "Cannot split secret: %s", gfsec_error_string(c));
for ( c = 0; c < cfg->n_shares; c++ ) {
gfsec_share_t *share;
share = cfg->shares[c];
if ( gfsec_scheme_module_put_file(share->scheme, share->authority,
share->path, share->data, share->len)
!= GFSEC_SCHEME_STATUS_SUCCESS )
errx(EXIT_FAILURE, "Cannot write share");
}
if ( (c = gfsec_write_config(cfg, config_path)) != 0 )
errx(EXIT_FAILURE, "Cannot write configuration file: %s",
gfsec_error_string(c));
gfsec_secret_free(cfg);
if ( ! keep_original )
unlink(argv[optind]);
return EXIT_SUCCESS;
}

181
src/gfsec-use.c

@ -32,14 +32,12 @@
#include <getopt.h>
#include <err.h>
#include <libgfshare.h>
#include <gcrypt.h>
#include "util.h"
#include "share.h"
#include "secret.h"
#include "secretcfg.h"
#include "mtp-support.h"
#include "uuid-support.h"
#include "scheme-module.h"
static void
usage(int status)
@ -124,64 +122,26 @@ get_config_file(const char *filename, char *buffer, size_t len)
return rc;
}
static char *
get_share_display_name(gfsec_share_t *share)
{
static char buffer[256];
char *schemes[] = { "file://", "uuid://", "label://", "mtp://" };
snprintf(buffer, sizeof(buffer), "%s%s%s",
schemes[share->scheme],
share->authority ? share->authority : "",
share->path);
return buffer;
}
static int
get_share_data(gfsec_share_t *share, gcry_md_hd_t md)
get_share_data(gfsec_share_t *share)
{
int rc = -1;
switch ( share->scheme ) {
case SCHEME_FILE:
if ( (share->data = read_file(share->path, &(share->length))) )
rc = 0;
break;
case SCHEME_UUID:
if ( (share->data = gfsec_get_file_from_uuid(share->authority,
share->path, &(share->length))) )
rc = 0;
break;
case SCHEME_LABEL:
if ( (share->data = gfsec_get_file_from_label(share->authority,
share->path, &(share->length))) )
rc = 0;
break;
case SCHEME_MTP:
if ( (share->data = gfsec_get_file_from_mtp(share->authority,
share->path, &(share->length))) )
rc = 0;
break;
}
int rc;
unsigned char *data;
char buffer[256];
size_t len;
if ( rc == 0 && share->sha256 ) {
unsigned char *md_val;
rc = gfsec_scheme_module_get_file(share->scheme, share->authority,
share->path, &data, &len);
gcry_md_write(md, share->data, share->length);
md_val = gcry_md_read(md, 0);
if ( rc == GFSEC_SCHEME_STATUS_SUCCESS ) {
gfsec_share_get_uri(share, buffer, sizeof(buffer));
if ( memcmp(share->sha256, md_val, 32) != 0 ) {
warnx("Incorrect hash value for share %s\n", get_share_display_name(share));
free(share->data);
share->data = NULL;
rc = -1;
if ( (rc = gfsec_share_set_data(share, data, len)) != 0 ) {
warnx("Cannot set data for share %s: %s", buffer, gfsec_error_string(rc));
free(data);
}
gcry_md_reset(md);
else
printf("Found share data in %s\n", buffer);
}
return rc;
@ -193,11 +153,9 @@ main(int argc, char **argv)
int c;
const char *cfg_file, *output_file;
char cfg_path[255];
gfsec_secret_config_t *cfg;
gfsec_share_t *share;
unsigned have_shares, have_full;
gfsec_secret_t *cfg;
pid_t pid;
gcry_md_hd_t md;
unsigned u;
struct option options[] = {
{ "help", 0, NULL, 'h' },
@ -209,7 +167,6 @@ main(int argc, char **argv)
setprogname(argv[0]);
cfg_file = output_file = NULL;
have_shares = have_full = 0;
while ( (c = getopt_long(argc, argv, "hvc:o:", options, NULL)) != -1 ) {
switch ( c ) {
@ -235,7 +192,7 @@ main(int argc, char **argv)
}
}
gfsec_mtp_init();
gfsec_scheme_module_init();
if ( ! gcry_check_version(GCRYPT_VERSION) )
errx(EXIT_FAILURE, "libgcrypt version mismatch");
@ -246,98 +203,34 @@ main(int argc, char **argv)
if ( get_config_file(cfg_file, cfg_path, sizeof(cfg_path)) == -1 )
err(EXIT_FAILURE, "Cannot find configuration file");
if ( ! (cfg = gfsec_read_config(cfg_path)) )
err(EXIT_FAILURE, "Cannot parse configuration file");
if ( ! output_file && ! (output_file = cfg->output_file) )
errx(EXIT_FAILURE, "No output file specified");
if ( gcry_md_open(&md, GCRY_MD_SHA256, 0) )
errx(EXIT_FAILURE, "Cannot create hashing context");
share = cfg->shares;
while ( share ) {
if ( get_share_data(share, md) == 0 ) {
if ( (share->flags & GFSEC_SHARE_FLAGS_FULL) > 0 )
have_full = 1;
else
have_shares += 1;
printf("Found share data in %s\n", get_share_display_name(share));
}
share = share->next;
if ( (c = gfsec_read_config(&cfg, cfg_path, &u)) != 0 ) {
if ( c == GFSEC_ERR_SYSTEM_ERROR )
err(EXIT_FAILURE, "Cannot read configuration file");
else
errx(EXIT_FAILURE, "%s (line %u): %s", cfg_path, u, gfsec_error_string(c));
}
gcry_md_close(md);
if ( have_full ) {
share = cfg->shares;
while ( share ) {
if ( share->data && (share->flags & GFSEC_SHARE_FLAGS_FULL) > 0 )
break;
share = share->next;
}
printf("Using full data in %s\n", get_share_display_name(share));
if ( write_file(output_file, share->data, share->length) == -1 )
err(EXIT_FAILURE, "Cannot write secret");
}
else if ( have_shares >= cfg->threshold ) {
gfshare_ctx *ctx;
unsigned char sharenrs[255], *secret;
unsigned n, size;
n = size = 0;
share = cfg->shares;
while ( share ) {
if ( share->data && share->share_nr > 0 ) {
sharenrs[n++] = share->share_nr;
if ( size == 0 )
size = share->length;
else if ( size != share->length )
errx(EXIT_FAILURE, "Shares have different sizes");
}
share = share->next;
}
if ( ! (secret = malloc(size)) || mlock(secret, size) == -1 )
err(EXIT_FAILURE, "Cannot allocated mlocked memory");
if ( ! (ctx = gfshare_ctx_init_dec(sharenrs, n, size)) )
errx(EXIT_FAILURE, "Cannot initialize libgfshare context");
if ( ! output_file && ! (output_file = cfg->filename) )
errx(EXIT_FAILURE, "No output file specified");
n = 0;
share = cfg->shares;
while ( share ) {
if ( share->data && share->share_nr > 0 ) {
printf("using share data in %s\n", get_share_display_name(share));
gfshare_ctx_dec_giveshare(ctx, n++, share->data);
}
for ( u = 0; u < cfg->n_shares; u++ )
get_share_data(cfg->shares[u]);
share = share->next;
}
if ( (c = gfsec_secret_can_combine(cfg)) != 0 )
errx(EXIT_FAILURE, "Cannot reconstitute secret: %s", gfsec_error_string(c));
gfshare_ctx_dec_extract(ctx, secret);
if ( write_file(output_file, secret, size) == -1 )
err(EXIT_FAILURE, "Cannot write secret");
if ( (c = gfsec_secret_combine(cfg)) != 0 )
errx(EXIT_FAILURE, "Error while reconstituting secret: %s", gfsec_error_string(c));
memset(secret, 0, size);
munlock(secret, size);
free(secret);
}
else
errx(EXIT_FAILURE, "Not enough data to reconstitute secret");
if ( write_file(output_file, cfg->data, cfg->len) == -1 )
err(EXIT_FAILURE, "Cannot write secret");
if ( (pid = fork()) == -1 ) {
unlink(cfg->output_file);
unlink(cfg->filename);
err(EXIT_FAILURE, "Cannot fork");
}
else if ( pid == 0 ) {
gfsec_destroy_config(cfg);
gfsec_secret_free(cfg);
if ( optind < argc ) {
execvp(argv[optind], &(argv[optind]));
@ -370,7 +263,7 @@ main(int argc, char **argv)
unlink(output_file);
}
gfsec_destroy_config(cfg);
gfsec_secret_free(cfg);
return EXIT_SUCCESS;
}

228
src/mtp-support.c

@ -1,228 +0,0 @@
/*
* gfsec - Secret sharing tools
* Copyright (C) 2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "mtp-support.h"
#ifndef HAVE_LIBMTP
#include <errno.h>
unsigned char *
gfsec_get_file_from_mtp(const char *authority,
const char *path,
size_t *len)
{
(void) authority;
(void) path;
(void) len;
errno = ENOSYS;
return NULL;
}
#else
#include <string.h>
#include <splitstr.h>
#define MTP_ROOT_FOLDER_ID 0xFFFFFFFF
/**
* Finds a connected MTP device with the specified serial number.
*
* @param[in] wanted_serial The serial number of the device to find.
*
* @return An object representing the found device (to be freed with
* LIBMTP_Release_Device), or NULL if no device was found.
*/
static LIBMTP_mtpdevice_t *
find_mtp_device(const char *wanted_serial)
{
LIBMTP_raw_device_t *raw_devices;
LIBMTP_mtpdevice_t *device;
int i, n;
if ( LIBMTP_Detect_Raw_Devices(&raw_devices, &n) != 0 )
return NULL;
for ( i = 0, device = NULL; i < n && device == NULL; i++ ) {
char *serial;
device = LIBMTP_Open_Raw_Device_Uncached(&(raw_devices[i]));
if ( (serial = LIBMTP_Get_Serialnumber(device)) == NULL ||
strcmp(serial, wanted_serial) != 0 ) {
LIBMTP_Release_Device(device);
device = NULL;
if ( serial )
free(serial);
}
}
free(raw_devices);
return device;
}
/**
* Finds a file on a given MTP device.
*
* @param[in] device The MTP device.
* @param[in] storage Storage identifier (0 to search in all storages).
* @param[in] path The path of the file to find.
* @param[out] size If not NULL and the file is found, this will be set
* to the size of the file.
*
* @return The MTP identifier for the file if found, or -1 if not found.
*/
static long
find_mtp_file(LIBMTP_mtpdevice_t *device,
unsigned storage,
const char *path,
size_t *size)
{
char **components;
size_t n;
unsigned i, file_id;
long rc = -1;
if ( ! (components = splitstr(path, '/', &n)) )
return -1;
for ( i = 0, file_id = MTP_ROOT_FOLDER_ID; i < n; i++ ) {
LIBMTP_file_t *files, *file;
int found = 0;
files = LIBMTP_Get_Files_And_Folders(device, storage, file_id);
file = files;
while ( file && ! found ) {
LIBMTP_file_t *tmp;
if ( strcmp(file->filename, components[i]) == 0 ) {
if ( file->filetype == LIBMTP_FILETYPE_FOLDER && i < n - 1 ) {
file_id = file->item_id;
found = 1;
}
else if ( file->filetype != LIBMTP_FILETYPE_FOLDER && i == n - 1 ) {
rc = file->item_id;
found = 1;
if ( size )
*size = file->filesize;
}
}
tmp = file;
file = file->next;
LIBMTP_destroy_file_t(tmp);
}
if ( ! found )
i = n; /* Exit loop. */
}
free(components);
return rc;
}
struct getfile_cb_data {
unsigned char *buffer;
unsigned written;
size_t expected;
};
/**
* Callback for the LIBMTP_Get_File_To_Handler function.
*
* @param params MTP parameters (unused).
* @param priv Pointer to a getfile_cb_data structure.
* @param sendlen Number of bytes available.
* @param data Actual bytes available.
* @param[out] putlen Number of bytes used.
*
* @return LIBMTP_HANLDER_RETURN_OK if successful, or
* LIBMTP_HANDLER_RETURN_ERROR if we get more bytes than we expected.
*/
static unsigned short
getfile_cb(void *params,
void *priv,
unsigned sendlen,
unsigned char *data,
unsigned *putlen)
{
struct getfile_cb_data *cb_data = priv;
(void) params;
if ( cb_data->written + sendlen > cb_data->expected )
return LIBMTP_HANDLER_RETURN_ERROR;
memcpy(cb_data->buffer + cb_data->written, data, sendlen);
cb_data->written += sendlen;
*putlen = sendlen;
return LIBMTP_HANDLER_RETURN_OK;
}
/**
* Gets the contents of a file on a MTP device.
*
* @param[in] authority Serial number of the MTP device.
* @param[in] path Path to the file on the MTP device.
* @param[out] len Number of bytes read from the device.
*
* @return A pointer to a newly allocated buffer containing
* the file data, or NULL if an error occured.
*/
unsigned char *
gfsec_get_file_from_mtp(const char *authority,
const char *path,
size_t *len)
{
LIBMTP_mtpdevice_t *device;
struct getfile_cb_data cb_data;
unsigned char *blob = NULL;
if ( (device = find_mtp_device(authority)) ) {
long file_id;
if ( (file_id = find_mtp_file(device, 0, path, len)) != -1 ) {
if ( (blob = malloc(*len)) ) {
cb_data.buffer = blob;
cb_data.written = 0;
cb_data.expected = *len;
if ( LIBMTP_Get_File_To_Handler(device, file_id,
getfile_cb, &cb_data, NULL, NULL) != 0 ) {
free(blob);
blob = NULL;
}
}
}
LIBMTP_Release_Device(device);
}
return blob;
}
#endif /* HAVE_LIBMTP */

68
src/scheme-file.c

@ -0,0 +1,68 @@
/*
* gfsecret - Secret sharing tools
* Copyright (C) 2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "scheme-file.h"
#include "scheme-module.h"
#include "util.h"
int
gfsec_scheme_file_get_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char **buffer,
size_t *len)
{
(void) authority;
if ( scheme != GFSEC_SCHEME_FILE )
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
if ( (*buffer = read_file(path, len, GFSEC_SECRET_MAX_SIZE)) ) {
return GFSEC_SCHEME_STATUS_SUCCESS;
}
else
return GFSEC_SCHEME_STATUS_ERROR;
}
int
gfsec_scheme_file_put_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char *buffer,
size_t len)
{
(void) authority;
if ( scheme != GFSEC_SCHEME_FILE )
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
if ( write_file(path, buffer, len) != -1 )
return GFSEC_SCHEME_STATUS_SUCCESS;
else
return GFSEC_SCHEME_STATUS_ERROR;
}
void
gfsec_scheme_file_lst_auth(FILE *f)
{
fprintf(f, "file:// Local filesystem\n");
}

50
src/scheme-file.h

@ -0,0 +1,50 @@
/*
* gfsecret - Secret sharing tools
* Copyright (C) 2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ICP20160821_SCHEME_FILE_H
#define ICP20160821_SCHEME_FILE_H
#include <stdio.h>
#include "schemes.h"
#ifdef __cpluscplus
extern "C" {
#endif
int
gfsec_scheme_file_get_file(gfsec_scheme_t,
const char *,
const char *,
unsigned char **,
size_t *);
int
gfsec_scheme_file_put_file(gfsec_scheme_t,
const char *,
const char *,
unsigned char *,
size_t);
void
gfsec_scheme_file_lst_auth(FILE *);
#ifdef __cplusplus
}
#endif
#endif /* !ICP20160821_SCHEME-FILE_H */

199
src/uuid-support.c → src/scheme-gio.c

@ -20,39 +20,10 @@
#include <config.h>
#endif
#include "uuid-support.h"
#include "scheme-gio.h"
#include "scheme-module.h"
#ifndef HAVE_GIO
#include <errno.h>
unsigned char *
gfsec_get_file_from_uuid(const char *authority,
const char *path,
size_t *len)
{
(void) authority;
(void) path;
(void) len;
errno = ENOSYS;
return NULL;
}
unsigned char *
gfsec_get_file_from_label(const char *authority,
const char *path,
size_t *len)
{
(void) authority;
(void) path;
(void) len;
errno = ENOSYS;
return NULL;
}
#else
#ifdef HAVE_GIO
#include <string.h>
#include <gio/gio.h>
@ -195,7 +166,7 @@ get_file_contents(GVolume *volume,
root_path = g_file_get_path(root);
full_path = g_strjoin("/", root_path, path, NULL);
if ( (*buffer = read_file(full_path, len)) )
if ( (*buffer = read_file(full_path, len, GFSEC_SECRET_MAX_SIZE)) )
rc = 0;
if ( was_mounted )
@ -211,56 +182,148 @@ get_file_contents(GVolume *volume,
}
/**
* Gets the contents of a file on a volume identified by its UUID.
* Write a file on the given volume.
*
* @param[in] authority The volume UUID.
* @param[in] path Path to the file on the volume.
* @param[out] len Number of bytes read from the volume.
* @param volume The volume on which the file should be written.
* @param path The pathname of the file to write.
* @param buffer The contents to write.
* @param len The size of the contents buffer.
*
* @return A pointer to a newly allocated buffer containing
* the file data, or NULL if an error occured.
* @return 0 if successful, -1 if an error occured.
*/
unsigned char *
gfsec_get_file_from_uuid(const char *authority,
const char *path,
size_t *len)
static int
put_file_contents(GVolume *volume,
const char *path,
unsigned char *buffer,
size_t len)
{
GMount *mount;
GFile *root;
char *root_path, *full_path;
int was_mounted, rc = -1;
if ( (mount = g_volume_get_mount(volume)) )
was_mounted = 1;
else if ( (mount = mount_volume(volume)) )
was_mounted = 0;
else
return -1;
root = g_mount_get_root(mount);
root_path = g_file_get_path(root);
full_path = g_strjoin("/", root_path, path, NULL);
if ( write_file(full_path, buffer, len) != -1 )
rc = 0;
if ( was_mounted )
g_object_unref(mount);
else
unmount_volume(mount);
g_free(full_path);
g_free(root_path);
g_object_unref(root);
return rc;
}
int
gfsec_scheme_gio_get_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char **buffer,
size_t *len)
{
GVolume *volume;
unsigned char *blob = NULL;
GVolume *volume = NULL;
int rc = GFSEC_SCHEME_STATUS_ERROR;
switch ( scheme ) {
case GFSEC_SCHEME_UUID:
volume = find_volume(authority, 1);
break;
if ( (volume = find_volume(authority, 1)) ) {
get_file_contents(volume, path, &blob, len);
case GFSEC_SCHEME_LABEL:
volume = find_volume(authority, 0);
break;
default:
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
}
if ( volume ) {
if ( get_file_contents(volume, path, buffer, len) == 0 )
rc = GFSEC_SCHEME_STATUS_SUCCESS;
g_object_unref(volume);
}
return blob;
return rc;
}
/**
* Gets the contents of a file on a volume identified by its label.
*
* @param[in] authority The volume label.
* @param[in] path Path to the file on the volume.
* @param[out] len Number of bytes read from the volume.
*
* @return A pointer to a newly allocated buffer containing
* the file data, or NULL if an error occured.
*/
unsigned char *
gfsec_get_file_from_label(const char *authority,
const char *path,
size_t *len)
int
gfsec_scheme_gio_put_file(gfsec_scheme_t scheme,
const char *authority,
const char *path,
unsigned char *buffer,
size_t len)
{
GVolume *volume;
unsigned char *blob = NULL;
GVolume *volume = NULL;
int rc = GFSEC_SCHEME_STATUS_ERROR;
if ( (volume = find_volume(authority, 0)) ) {
get_file_contents(volume, path, &blob, len);
switch ( scheme ) {
case GFSEC_SCHEME_UUID:
volume = find_volume(authority, 1);
break;
case GFSEC_SCHEME_LABEL:
volume = find_volume(authority, 0);
break;
default:
return GFSEC_SCHEME_STATUS_UNSUPPORTED_SCHEME;
}
if ( volume ) {
if ( put_file_contents(volume, path, buffer, len) == 0 )
rc = GFSEC_SCHEME_STATUS_SUCCESS;
g_object_unref(volume);
}
return blob;
return rc;
}
void
gfsec_scheme_gio_lst_auth(FILE *f)
{
GVolumeMonitor *volmon;
GList *volumes, *l;
volmon = g_volume_monitor_get();
volumes = g_volume_monitor_get_volumes(volmon);
for ( l = volumes; l != NULL; l = l->next ) {
char *label, *uuid;
GVolume *volume;
volume = G_VOLUME(l->data);
label = g_volume_get_name(volume);
uuid = g_volume_get_uuid(volume);
if ( label ) {
fprintf(f, "label://%s GIO volume\n", label);
free(label);
}
if ( uuid ) {
fprintf(f, "uuid://%s GIO volume\n", uuid);
free(uuid);
}
g_object_unref(l->data);
}
g_list_free(volumes);
g_object_unref(volmon);
}
#endif /* HAVE_GIO */

32
src/mtp-support.h → src/scheme-gio.h

@ -16,27 +16,35 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ICP20160207_MTP_SUPPORT_H
#define ICP20160207_MTP_SUPPORT_H
#ifndef ICP20160207_SCHEME_GIO_H
#define ICP20160207_SCHEME_GIO_H
#include <stdlib.h>
#include <stdio.h>
#include "schemes.h"
#ifdef __cpluscplus
extern "C" {
#endif
#ifdef HAVE_LIBMTP
#include <libmtp.h>
#define gfsec_mtp_init() LIBMTP_Init()
#else
#define gfsec_mtp_init()
#endif
int
gfsec_scheme_gio_get_file(gfsec_scheme_t,
const char *,
const char *,
unsigned char **,
size_t *);
int
gfsec_scheme_gio_put_file(gfsec_scheme_t,
const char *,
const char *,
unsigned char *,
size_t);
unsigned char *
gfsec_get_file_from_mtp(const char *, const char *, size_t *);
void
gfsec_scheme_gio_lst_auth(FILE *);
#ifdef __cplusplus
}
#endif
#endif /* !ICP20160207_MTP_SUPPORT_H */
#endif /* !ICP20160207_SCHEME_GIO_H */

420
src/scheme-libmtp.c

@ -0,0 +1,420 @@
/*
* gfsec - Secret sharing tools
* Copyright (C) 2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "scheme-libmtp.h"