From 23f70ce95419258604c91ecc946b1164954ba990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se> Date: Tue, 25 Jun 2013 13:47:08 +0200 Subject: [PATCH] New program nettle-pbkdf2. --- ChangeLog | 6 ++ testsuite/Makefile.in | 2 +- testsuite/nettle-pbkdf2-test | 29 ++++++ tools/Makefile.in | 10 +- tools/nettle-pbkdf2.c | 180 +++++++++++++++++++++++++++++++++++ 5 files changed, 224 insertions(+), 3 deletions(-) create mode 100755 testsuite/nettle-pbkdf2-test create mode 100644 tools/nettle-pbkdf2.c diff --git a/ChangeLog b/ChangeLog index d6327ab7..a7af3865 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2013-06-25 Niels Möller <nisse@lysator.liu.se> + * tools/nettle-pbkdf2.c: New command line tool. + * tools/Makefile.in (TARGETS): Added nettle-pbkdf2. + (nettle-pbkdf2$(EXEEXT)): New target. + * testsuite/nettle-pbkdf2-test: New test case. + * testsuite/Makefile.in (TS_SH): Added nettle-pbkdf2-test. + * tools/nettle-hash.c (digest_file): Use stack allocation for the small hex output buffer. diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 91f6e2a3..bf0e53c6 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -47,7 +47,7 @@ TS_HOGWEED = $(TS_HOGWEED_SOURCES:.c=$(EXEEXT)) TS_C = $(TS_NETTLE) @IF_HOGWEED@ $(TS_HOGWEED) TS_CXX = @IF_CXX@ $(CXX_SOURCES:.cxx=$(EXEEXT)) TARGETS = $(TS_C) $(TS_CXX) -TS_SH = sexp-conv-test pkcs1-conv-test symbols-test +TS_SH = sexp-conv-test pkcs1-conv-test nettle-pbkdf2-test symbols-test TS_ALL = $(TARGETS) $(TS_SH) EXTRA_SOURCES = sha1-huge-test.c EXTRA_TARGETS = $(EXTRA_SOURCES:.c=$(EXEEXT)) diff --git a/testsuite/nettle-pbkdf2-test b/testsuite/nettle-pbkdf2-test new file mode 100755 index 00000000..a1e26380 --- /dev/null +++ b/testsuite/nettle-pbkdf2-test @@ -0,0 +1,29 @@ +#! /bin/sh + +if [ -z "$srcdir" ] ; then + srcdir=`pwd` +fi + +test_pbkdf2 () { + password="$1" + salt="$2" + iters="$3" + expected="$4" + length=`expr ${#expected} / 2` + + printf "%s" "$password" | $EMULATOR ../tools/nettle-pbkdf2 \ + -i "$iters" -l "$length" "$salt" > test1.out + echo "$expected" > test2.out + + if cmp test1.out test2.out ; then + true + else + exit 1; + fi +} + +test_pbkdf2 passwd salt 1 "55ac046e56e3089f ec1691c22544b605" +test_pbkdf2 Password NaCl 80000 "4ddcd8f60b98be21 830cee5ef22701f9" + +exit 0 + diff --git a/tools/Makefile.in b/tools/Makefile.in index 29d55e88..f7b33529 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -18,7 +18,8 @@ PRE_CPPFLAGS = -I.. -I$(top_srcdir) PRE_LDFLAGS = -L.. HOGWEED_TARGETS = pkcs1-conv$(EXEEXT) -TARGETS = sexp-conv$(EXEEXT) nettle-hash$(EXEEXT) nettle-lfib-stream$(EXEEXT) \ +TARGETS = sexp-conv$(EXEEXT) nettle-hash$(EXEEXT) nettle-pbkdf2$(EXEEXT) \ + nettle-lfib-stream$(EXEEXT) \ @IF_HOGWEED@ $(HOGWEED_TARGETS) all: $(TARGETS) @@ -28,6 +29,7 @@ getopt_OBJS = ../getopt.$(OBJEXT) ../getopt1.$(OBJEXT) sexp_conv_SOURCES = sexp-conv.c input.c output.c parse.c misc.c pkcs1_conv_SOURCES = pkcs1-conv.c misc.c nettle_hash_SOURCES = nettle-hash.c misc.c +nettle_pbkdf2_SOURCES = nettle-pbkdf2.c misc.c SOURCES = $(sexp_conv_SOURCES) nettle-hash.c nettle-lfib-stream.c pkcs1-conv.c @@ -47,7 +49,11 @@ pkcs1-conv$(EXEEXT): $(pkcs1_conv_OBJS) ../libnettle.a ../libhogweed.a # FIXME: Avoid linking with gmp nettle_hash_OBJS = $(nettle_hash_SOURCES:.c=.$(OBJEXT)) $(getopt_OBJS) nettle-hash$(EXEEXT): $(nettle_hash_OBJS) ../libnettle.a - $(LINK) $(nettle_hash_OBJS) -lnettle $(LIBS) -o $@ + $(LINK) $(nettle_hash_OBJS) -lnettle -o $@ + +nettle_pbkdf2_OBJS = $(nettle_pbkdf2_SOURCES:.c=.$(OBJEXT)) $(getopt_OBJS) +nettle-pbkdf2$(EXEEXT): $(nettle_pbkdf2_OBJS) ../libnettle.a + $(LINK) $(nettle_pbkdf2_OBJS) -lnettle -o $@ .c.$(OBJEXT): diff --git a/tools/nettle-pbkdf2.c b/tools/nettle-pbkdf2.c new file mode 100644 index 00000000..35c98707 --- /dev/null +++ b/tools/nettle-pbkdf2.c @@ -0,0 +1,180 @@ +/* nettle-pbkdf2.c + * + * Command-line tool for pbkdf2 hashing. */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2013 Niels Möller + * + * The nettle library 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. + * + * The nettle library 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 a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pbkdf2.h" +#include "base16.h" + +#include "getopt.h" +#include "misc.h" + +#define DEFAULT_ITERATIONS 10000 +#define DEFAULT_LENGTH 16 +static void +usage (FILE *f) +{ + fprintf(f, "nettle-pbkdf2 [OPTIONS] SALT\n" + "Options:\n" + " --help Show this help.\n" + " -V, --version Show version information.\n" + " -i, --iterations=COUNT Desired iteration count (default %d).\n" + " -l, --length=LENGTH Desired output length (octets, default %d)\n" + " --raw Raw binary output.\n" + " --hex-salt Use hex encoding for the salt.\n", + DEFAULT_ITERATIONS, DEFAULT_LENGTH); +} + +#define MAX_PASSWORD 1024 + +int +main (int argc, char **argv) +{ + unsigned iterations = DEFAULT_ITERATIONS; + unsigned output_length = DEFAULT_LENGTH; + char password[MAX_PASSWORD]; + size_t password_length; + char *output; + size_t salt_length; + char *salt; + int raw = 0; + int hex_salt = 0; + int c; + + enum { OPT_HELP = 0x300, OPT_RAW, OPT_HEX_SALT }; + static const struct option options[] = + { + /* Name, args, flag, val */ + { "help", no_argument, NULL, OPT_HELP }, + { "version", no_argument, NULL, 'V' }, + { "length", required_argument, NULL, 'l' }, + { "iterations", required_argument, NULL, 'i' }, + { "raw", no_argument, NULL, OPT_RAW }, + { "hex-salt", no_argument, NULL, OPT_HEX_SALT }, + + { NULL, 0, NULL, 0 } + }; + + while ( (c = getopt_long(argc, argv, "Vl:i:", options, NULL)) != -1) + switch (c) + { + default: + abort(); + case OPT_HELP: + usage (stdout); + return EXIT_SUCCESS; + case 'V': + printf("nettle-pbkdf2 (" PACKAGE_STRING ")\n"); + return EXIT_SUCCESS; + case 'l': + { + int arg; + arg = atoi (optarg); + if (arg <= 0) + die ("Invalid length argument: `%s'\n", optarg); + + output_length = arg; + } + break; + case 'i': + { + int arg; + arg = atoi (optarg); + if (arg <= 0) + die ("Invalid iteration count: `%s'\n", optarg); + iterations = arg; + } + break; + case OPT_RAW: + raw = 1; + break; + case OPT_HEX_SALT: + hex_salt = 1; + break; + } + argv += optind; + argc -= optind; + + if (argc != 1) + { + usage (stderr); + return EXIT_FAILURE; + } + + salt = strdup (argv[0]); + salt_length = strlen(salt); + + if (hex_salt) + { + struct base16_decode_ctx base16; + + base16_decode_init (&base16); + if (!base16_decode_update (&base16, + &salt_length, + salt, salt_length, salt) + || !base16_decode_final (&base16)) + die ("Invalid salt (expecting hex encoding).\n"); + } + + password_length = fread (password, 1, sizeof(password), stdin); + if (password_length == sizeof(password)) + die ("Password input to long. Current limit is %d characters.\n", + (int) sizeof(password) - 1); + if (ferror (stdin)) + die ("Reading password input failed: %s.\n", strerror (errno)); + + output = xalloc (output_length); + pbkdf2_hmac_sha256 (password_length, password, iterations, salt_length, salt, + output_length, output); + + free (salt); + + if (raw) + fwrite (output, output_length, 1, stdout); + else + { + unsigned i; + char hex[BASE16_ENCODE_LENGTH(8) + 1]; + for (i = 0; i + 8 < output_length; i += 8) + { + base16_encode_update(hex, 8, output + i); + hex[BASE16_ENCODE_LENGTH(8)] = 0; + printf("%s%c", hex, i % 64 == 56 ? '\n' : ' '); + } + base16_encode_update(hex, output_length - i, output + i); + hex[BASE16_ENCODE_LENGTH(output_length - i)] = 0; + printf("%s\n", hex); + } + if (fflush(stdout) != 0 ) + die("Write failed: %s\n", STRERROR(errno)); + + return EXIT_SUCCESS; +} -- GitLab