projects/sencrypt

changeset 0:73af139d1a94

Initial revision
author Guido Berhoerster <guido+sencrypt@berhoerster.name>
date Tue Jan 28 19:23:16 2014 +0100 (2014-01-28)
parents
children f0ceb0ad20e7
files Makefile README deps.sed err.c err.h sencrypt.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Tue Jan 28 19:23:16 2014 +0100
     1.3 @@ -0,0 +1,92 @@
     1.4 +#
     1.5 +# Copyright (C) 2014 Guido Berhoerster <guido+sencrypt@berhoerster.name>
     1.6 +#
     1.7 +# Permission is hereby granted, free of charge, to any person obtaining
     1.8 +# a copy of this software and associated documentation files (the
     1.9 +# "Software"), to deal in the Software without restriction, including
    1.10 +# without limitation the rights to use, copy, modify, merge, publish,
    1.11 +# distribute, sublicense, and/or sell copies of the Software, and to
    1.12 +# permit persons to whom the Software is furnished to do so, subject to
    1.13 +# the following conditions:
    1.14 +#
    1.15 +# The above copyright notice and this permission notice shall be included
    1.16 +# in all copies or substantial portions of the Software.
    1.17 +#
    1.18 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    1.19 +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    1.20 +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    1.21 +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    1.22 +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    1.23 +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    1.24 +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    1.25 +#
    1.26 +
    1.27 +PACKAGE =	sencrypt
    1.28 +VERSION =	1
    1.29 +DISTNAME :=	$(PACKAGE)-$(VERSION)
    1.30 +DECRYPT_ALIAS =	sdecrypt
    1.31 +
    1.32 +COMPILE.c =	$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS) $(TARGET_ARCH) -c
    1.33 +# gcc, clang, icc
    1.34 +MAKEDEPEND.c =	$(CC) -MM $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS)
    1.35 +# Sun/Solaris Studio
    1.36 +#MAKEDEPEND.c =	$(CC) -xM1 $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS)
    1.37 +# X makedepend
    1.38 +#MAKEDEPEND.c =	makedepend -f- -Y -- $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS) --
    1.39 +LINK.c =	$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(XCPPFLAGS) $(LDFLAGS) $(XLDFLAGS) $(TARGET_ARCH)
    1.40 +LINK.o =	$(CC) $(LDFLAGS) $(XLDFLAGS) $(TARGET_ARCH)
    1.41 +INSTALL :=	install
    1.42 +INSTALL.exec :=	$(INSTALL) -D -m 0755
    1.43 +INSTALL.data :=	$(INSTALL) -D -m 0644
    1.44 +PAX :=		pax
    1.45 +GZIP :=		gzip
    1.46 +SED :=		sed
    1.47 +
    1.48 +DESTDIR ?=
    1.49 +prefix ?=	/usr/local
    1.50 +bindir ?=	$(prefix)/bin
    1.51 +datadir ?=	$(prefix)/share
    1.52 +
    1.53 +HAVE_ERR_H ?=	1
    1.54 +
    1.55 +OBJS =		sencrypt.o
    1.56 +
    1.57 +ifeq ($(HAVE_ERR_H),0)
    1.58 +  OBJS +=	err.o
    1.59 +endif
    1.60 +
    1.61 +.DEFAULT_TARGET = all
    1.62 +
    1.63 +.PHONY: all clean clobber dist install
    1.64 +
    1.65 +all: $(PACKAGE)
    1.66 +
    1.67 +$(PACKAGE): XCPPFLAGS :=	-DOPENSSL_LOAD_CONF
    1.68 +ifeq ($(HAVE_ERR_H),1)
    1.69 +    $(PACKAGE): XCPPFLAGS +=	-DHAVE_ERR_H
    1.70 +endif
    1.71 +$(PACKAGE): XCFLAGS :=	$(shell getconf LFS_CFLAGS)
    1.72 +$(PACKAGE): LDLIBS :=	-lcrypto
    1.73 +$(PACKAGE): XLDFLAGS :=	$(shell getconf LFS_LDFLAGS)
    1.74 +$(PACKAGE): $(OBJS)
    1.75 +	$(LINK.o) $^ $(LDLIBS) -o $@
    1.76 +
    1.77 +%.o: %.c
    1.78 +	$(MAKEDEPEND.c) $< | $(SED) -f deps.sed >$*.d
    1.79 +	$(COMPILE.c) -o $@ $<
    1.80 +
    1.81 +install:
    1.82 +	$(INSTALL.exec) $(PACKAGE) "$(DESTDIR)$(bindir)/$(PACKAGE)"
    1.83 +	ln -f $(PACKAGE) "$(DESTDIR)$(bindir)/$(DECRYPT_ALIAS)"
    1.84 +
    1.85 +clean:
    1.86 +	rm -f $(PACKAGE) $(OBJS)
    1.87 +
    1.88 +clobber: clean
    1.89 +	rm -f $(patsubst %.o,%.d,$(OBJS))
    1.90 +
    1.91 +dist: clobber
    1.92 +	$(PAX) -w -x ustar -s ',.*/\..*,,' -s ',./[^/]*\.tar\.gz,,' \
    1.93 +	    -s ',\./,$(DISTNAME)/,' . | $(GZIP) > $(DISTNAME).tar.gz
    1.94 +
    1.95 +-include $(patsubst %.o,%.d,$(OBJS))
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/README	Tue Jan 28 19:23:16 2014 +0100
     2.3 @@ -0,0 +1,48 @@
     2.4 +sencrypt
     2.5 +========
     2.6 +
     2.7 +Description
     2.8 +-----------
     2.9 +
    2.10 +sencrypt and sdecrypt are utilities for encrypting and decrypting data with the
    2.11 +AES, DES, 3DES, and RC4 algorithms. It can read keys from files or ask for a
    2.12 +passphrase and use that together with a salt to derive a key using the PBKDF2
    2.13 +key derivation function.
    2.14 +
    2.15 +sencrypt and sdecrypt are portable and compatible reimplementations of the
    2.16 +encrypt and decrypt utilities in Solaris/Illumos-based operating systems.
    2.17 +
    2.18 +Build Instructions
    2.19 +------------------
    2.20 +
    2.21 +sencrypt requires a POSIX:2004 compatible operating system, and needs GNU make,
    2.22 +GNU or BSD install, and the OpenSSL library to be installed. It has been tested
    2.23 +on Linux distributions, FreeBSD, Solaris and Illumos-derived distributions,
    2.24 +UnixWare, and OpenServer.
    2.25 +
    2.26 +License
    2.27 +-------
    2.28 +
    2.29 +Except otherwise noted, all files are Copyright (C) 2014 Guido Berhoerster and
    2.30 +distributed under the following license terms:
    2.31 +
    2.32 +Copyright (C) 2014 Guido Berhoerster <guido+sencrypt@berhoerster.name>
    2.33 +
    2.34 +Permission is hereby granted, free of charge, to any person obtaining
    2.35 +a copy of this software and associated documentation files (the
    2.36 +"Software"), to deal in the Software without restriction, including
    2.37 +without limitation the rights to use, copy, modify, merge, publish,
    2.38 +distribute, sublicense, and/or sell copies of the Software, and to
    2.39 +permit persons to whom the Software is furnished to do so, subject to
    2.40 +the following conditions:
    2.41 +
    2.42 +The above copyright notice and this permission notice shall be included
    2.43 +in all copies or substantial portions of the Software.
    2.44 +
    2.45 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    2.46 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    2.47 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    2.48 +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    2.49 +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    2.50 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    2.51 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/deps.sed	Tue Jan 28 19:23:16 2014 +0100
     3.3 @@ -0,0 +1,26 @@
     3.4 +/^[^:]\{1,\}:.*\\$/{
     3.5 +    h
     3.6 +    s/\([^:]\{1,\}:\).*/\1/
     3.7 +    x
     3.8 +    s/[^:]\{1,\}://
     3.9 +}
    3.10 +/\\$/,/^$/bgen
    3.11 +/\\$/,/[^\\]$/{
    3.12 +:gen
    3.13 +    s/[[:blank:]]*\\$//
    3.14 +    s/^[[:blank:]]*//
    3.15 +    G
    3.16 +    s/\(.*\)\n\(.*\)/\2 \1/
    3.17 +}
    3.18 +/^[^:]\{1,\}:[[:blank:]]*$/d
    3.19 +/^[^:]\{1,\}\.o:/{
    3.20 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.[cC][[:blank:]]*/ /g
    3.21 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.[cC]$//g
    3.22 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cc[[:blank:]]*/ /g
    3.23 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cc$//g
    3.24 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cpp[[:blank:]]*/ /g
    3.25 +    s/[[:blank:]]*[^[:blank:]]\{1,\}\.cpp$//g
    3.26 +    /^[^:]\{1,\}:[[:blank:]]*$/d
    3.27 +    s/^\([^:]\{1,\}\)\.o[[:blank:]]*:[[:blank:]]*\(.*\)/\1.d: $(wildcard \2)\
    3.28 +&/
    3.29 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/err.c	Tue Jan 28 19:23:16 2014 +0100
     4.3 @@ -0,0 +1,115 @@
     4.4 +/*
     4.5 + * Copyright (C) 2011 Guido Berhoerster <guido+sencrypt@berhoerster.name>
     4.6 + *
     4.7 + * Permission is hereby granted, free of charge, to any person obtaining
     4.8 + * a copy of this software and associated documentation files (the
     4.9 + * "Software"), to deal in the Software without restriction, including
    4.10 + * without limitation the rights to use, copy, modify, merge, publish,
    4.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    4.12 + * permit persons to whom the Software is furnished to do so, subject to
    4.13 + * the following conditions:
    4.14 + *
    4.15 + * The above copyright notice and this permission notice shall be included
    4.16 + * in all copies or substantial portions of the Software.
    4.17 + *
    4.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    4.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    4.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    4.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    4.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    4.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    4.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    4.25 + */
    4.26 +
    4.27 +#include <stdlib.h>
    4.28 +#include <stdio.h>
    4.29 +#include <string.h>
    4.30 +#include <errno.h>
    4.31 +
    4.32 +#include "err.h"
    4.33 +
    4.34 +static char __progname[] = "unknown";
    4.35 +
    4.36 +void
    4.37 +err(int eval, const char *fmt, ...)
    4.38 +{
    4.39 +	va_list args;
    4.40 +
    4.41 +	va_start(args, fmt);
    4.42 +	vwarn(fmt, args);
    4.43 +	va_end(args);
    4.44 +
    4.45 +	exit(eval);
    4.46 +}
    4.47 +
    4.48 +void
    4.49 +errx(int eval, const char *fmt, ...)
    4.50 +{
    4.51 +	va_list args;
    4.52 +
    4.53 +	va_start(args, fmt);
    4.54 +	vwarnx(fmt, args);
    4.55 +	va_end(args);
    4.56 +
    4.57 +	exit(eval);
    4.58 +}
    4.59 +
    4.60 +void
    4.61 +warn(const char *fmt, ...)
    4.62 +{
    4.63 +	va_list args;
    4.64 +
    4.65 +	va_start(args, fmt);
    4.66 +	vwarn(fmt, args);
    4.67 +	va_end(args);
    4.68 +}
    4.69 +
    4.70 +void
    4.71 +warnx(const char *fmt, ...)
    4.72 +{
    4.73 +	va_list args;
    4.74 +
    4.75 +	va_start(args, fmt);
    4.76 +	vwarnx(fmt, args);
    4.77 +	va_end(args);
    4.78 +}
    4.79 +
    4.80 +void
    4.81 +verr(int eval, const char *fmt, va_list args)
    4.82 +{
    4.83 +	vwarn(fmt, args);
    4.84 +
    4.85 +	exit(eval);
    4.86 +}
    4.87 +
    4.88 +void
    4.89 +verrx(int eval, const char *fmt, va_list args)
    4.90 +{
    4.91 +	vwarnx(fmt, args);
    4.92 +
    4.93 +	exit(eval);
    4.94 +}
    4.95 +
    4.96 +void
    4.97 +vwarn(const char *fmt, va_list args)
    4.98 +{
    4.99 +	int old_errno = errno;
   4.100 +
   4.101 +	fprintf(stderr, "%s: ", __progname);
   4.102 +	if (fmt != NULL) {
   4.103 +		vfprintf(stderr, fmt, args);
   4.104 +		fprintf(stderr, ": ");
   4.105 +	}
   4.106 +	fprintf(stderr, "%s\n", strerror(old_errno));
   4.107 +	errno = old_errno;
   4.108 +}
   4.109 +
   4.110 +void
   4.111 +vwarnx(const char *fmt, va_list args)
   4.112 +{
   4.113 +	fprintf(stderr, "%s: ", __progname);
   4.114 +	if (fmt != NULL) {
   4.115 +		vfprintf(stderr, fmt, args);
   4.116 +	}
   4.117 +	fputc('\n', stderr);
   4.118 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/err.h	Tue Jan 28 19:23:16 2014 +0100
     5.3 @@ -0,0 +1,38 @@
     5.4 +/*
     5.5 + * Copyright (C) 2011 Guido Berhoerster <guido+sencrypt@berhoerster.name>
     5.6 + *
     5.7 + * Permission is hereby granted, free of charge, to any person obtaining
     5.8 + * a copy of this software and associated documentation files (the
     5.9 + * "Software"), to deal in the Software without restriction, including
    5.10 + * without limitation the rights to use, copy, modify, merge, publish,
    5.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    5.12 + * permit persons to whom the Software is furnished to do so, subject to
    5.13 + * the following conditions:
    5.14 + *
    5.15 + * The above copyright notice and this permission notice shall be included
    5.16 + * in all copies or substantial portions of the Software.
    5.17 + *
    5.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    5.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    5.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    5.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    5.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    5.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    5.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    5.25 + */
    5.26 +
    5.27 +#ifndef ERR_H
    5.28 +#define ERR_H
    5.29 +
    5.30 +#include <stdarg.h>
    5.31 +
    5.32 +void err(int, const char *, ...);
    5.33 +void errx(int, const char *, ...);
    5.34 +void warn(const char *, ...);
    5.35 +void warnx(const char *, ...);
    5.36 +void verr(int, const char *, va_list);
    5.37 +void verrx(int, const char *, va_list);
    5.38 +void vwarn(const char *, va_list);
    5.39 +void vwarnx(const char *, va_list);
    5.40 +
    5.41 +#endif /* ERR_H */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/sencrypt.c	Tue Jan 28 19:23:16 2014 +0100
     6.3 @@ -0,0 +1,815 @@
     6.4 +/*
     6.5 + * Copyright (C) 2011 Guido Berhoerster <guido+sencrypt@berhoerster.name>
     6.6 + *
     6.7 + * Permission is hereby granted, free of charge, to any person obtaining
     6.8 + * a copy of this software and associated documentation files (the
     6.9 + * "Software"), to deal in the Software without restriction, including
    6.10 + * without limitation the rights to use, copy, modify, merge, publish,
    6.11 + * distribute, sublicense, and/or sell copies of the Software, and to
    6.12 + * permit persons to whom the Software is furnished to do so, subject to
    6.13 + * the following conditions:
    6.14 + *
    6.15 + * The above copyright notice and this permission notice shall be included
    6.16 + * in all copies or substantial portions of the Software.
    6.17 + *
    6.18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    6.19 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    6.20 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    6.21 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    6.22 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    6.23 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    6.24 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    6.25 + */
    6.26 +
    6.27 +#define	_XOPEN_SOURCE	600
    6.28 +
    6.29 +#include <stdio.h>
    6.30 +#include <string.h>
    6.31 +#include <stdint.h>
    6.32 +#include <stdbool.h>
    6.33 +#include <unistd.h>
    6.34 +#include <limits.h>
    6.35 +#include <libgen.h>
    6.36 +#include <arpa/inet.h>
    6.37 +#include <sys/stat.h>
    6.38 +#include <openssl/conf.h>
    6.39 +#include <openssl/rand.h>
    6.40 +#include <openssl/evp.h>
    6.41 +#include <openssl/err.h>
    6.42 +
    6.43 +#ifdef HAVE_ERR_H
    6.44 +#include <err.h>
    6.45 +#else
    6.46 +#include "err.h"
    6.47 +#endif /* HAVE_ERR_H */
    6.48 +
    6.49 +#define	MAX(a, b)	(((a) > (b)) ? (a) : (b))
    6.50 +
    6.51 +#define	EXIT_USAGE	2
    6.52 +
    6.53 +#define	SENCRYPT_FORMAT_VERSION	1
    6.54 +#define	PBKDF2_ITERATIONS	1000
    6.55 +#define	SALT_LEN		16
    6.56 +#define	BUFFER_SIZE		(16 * 1024)
    6.57 +#define	MAX_PASSWORD_LEN	256
    6.58 +
    6.59 +enum {
    6.60 +	CMD_SENCRYPT,
    6.61 +	CMD_SDECRYPT
    6.62 +};
    6.63 +
    6.64 +static void
    6.65 +openssl_warn(void) {
    6.66 +	unsigned long	errcode;
    6.67 +
    6.68 +	while ((errcode = ERR_get_error()) != 0) {
    6.69 +		warnx("%s", ERR_error_string(errcode, NULL));
    6.70 +	}
    6.71 +}
    6.72 +
    6.73 +static size_t
    6.74 +read_keyfile(const char *filename, unsigned char *key, size_t key_size_max)
    6.75 +{
    6.76 +	size_t		keyfile_size = 0;
    6.77 +	FILE		*fp = NULL;
    6.78 +	struct		stat statbuf;
    6.79 +
    6.80 +	fp = fopen(filename, "r");
    6.81 +	if (fp == NULL) {
    6.82 +		warn("could not open key file \"%s\"", filename);
    6.83 +		goto out;
    6.84 +	}
    6.85 +
    6.86 +	if (fstat(fileno(fp), &statbuf) == -1) {
    6.87 +		warn("could not stat key file \"%s\"", filename);
    6.88 +		goto out;
    6.89 +	}
    6.90 +
    6.91 +	if (!S_ISREG(statbuf.st_mode)) {
    6.92 +		warnx("key file \"%s\" is not a regular file", filename);
    6.93 +		goto out;
    6.94 +	}
    6.95 +
    6.96 +	if ((uintmax_t)statbuf.st_size > SIZE_MAX) {
    6.97 +		warnx("key file \"%s\" is too large", filename);
    6.98 +		goto out;
    6.99 +	}
   6.100 +	keyfile_size = (size_t)statbuf.st_size;
   6.101 +	if ((keyfile_size > key_size_max) ||
   6.102 +	    (keyfile_size == 0)) {
   6.103 +		warnx("invalid key size");
   6.104 +		goto out;
   6.105 +	}
   6.106 +
   6.107 +	if (fread(key, 1, keyfile_size, fp) != keyfile_size) {
   6.108 +		warnx("could not read key file \"%s\"", filename);
   6.109 +		goto out;
   6.110 +	}
   6.111 +
   6.112 +out:
   6.113 +	if (fp != NULL) {
   6.114 +		fclose(fp);
   6.115 +	}
   6.116 +
   6.117 +	return (keyfile_size);
   6.118 +}
   6.119 +
   6.120 +static int
   6.121 +find_algorithm(const char *algo_name, const EVP_CIPHER **cipher_ptr,
   6.122 +    size_t *key_len_ptr)
   6.123 +{
   6.124 +	int	retval = 0;
   6.125 +	const EVP_CIPHER	*cipher = NULL;
   6.126 +	size_t	key_len = *key_len_ptr;
   6.127 +
   6.128 +	if (strcmp(algo_name, "aes") == 0) {
   6.129 +		switch (key_len) {
   6.130 +		case 0:
   6.131 +			key_len = 16;
   6.132 +		case 16:
   6.133 +			cipher = EVP_aes_128_cbc();
   6.134 +			break;
   6.135 +		case 24:
   6.136 +			cipher = EVP_aes_192_cbc();
   6.137 +			break;
   6.138 +		case 32:
   6.139 +			cipher = EVP_aes_256_cbc();
   6.140 +			break;
   6.141 +		default:
   6.142 +			warnx("invalid key length %zu", key_len);
   6.143 +			retval = -1;
   6.144 +		}
   6.145 +	} else if (strcmp(algo_name, "arcfour") == 0) {
   6.146 +		if (key_len == 0) {
   6.147 +			key_len = 16;
   6.148 +			cipher = EVP_rc4();
   6.149 +		} else if (key_len <= EVP_MAX_KEY_LENGTH) {
   6.150 +			/*
   6.151 +			 * for RC4 keys are not used verbatim but dervied using
   6.152 +			 * PBKDF2 with a hardcoded key length of 128 bit
   6.153 +			 */
   6.154 +			key_len = 16;
   6.155 +			cipher = EVP_rc4();
   6.156 +		} else {
   6.157 +			warnx("invalid key length %zu", key_len);
   6.158 +			retval = -1;
   6.159 +		}
   6.160 +	} else if (strcmp(algo_name, "des") == 0) {
   6.161 +		if (key_len == 0) {
   6.162 +			key_len = 8;
   6.163 +			cipher = EVP_des_cbc();
   6.164 +		} else if (key_len == 8) {
   6.165 +			cipher = EVP_des_cbc();
   6.166 +		} else {
   6.167 +			warnx("invalid key length %zu", key_len);
   6.168 +			retval = -1;
   6.169 +		}
   6.170 +	} else if (strcmp(algo_name, "3des") == 0) {
   6.171 +		if (key_len == 0) {
   6.172 +			key_len = 24;
   6.173 +			cipher = EVP_des_ede3_cbc();
   6.174 +		} else if (key_len == 24) {
   6.175 +			cipher = EVP_des_ede3_cbc();
   6.176 +		} else {
   6.177 +			warnx("invalid key length %zu", key_len);
   6.178 +			retval = -1;
   6.179 +		}
   6.180 +	} else {
   6.181 +		warnx("unknown algorithm \"%s\"", algo_name);
   6.182 +		retval = -1;
   6.183 +	}
   6.184 +
   6.185 +	*cipher_ptr = cipher;
   6.186 +	*key_len_ptr = key_len;
   6.187 +
   6.188 +	return (retval);
   6.189 +}
   6.190 +
   6.191 +static int
   6.192 +read_header(BIO *bio_in, uint32_t *iterations, unsigned char *iv, int iv_len,
   6.193 +    unsigned char *salt, int salt_len)
   6.194 +{
   6.195 +	int		read_len;
   6.196 +	uint32_t	version;
   6.197 +	int		retval = 0;
   6.198 +
   6.199 +	read_len = BIO_read(bio_in, &version, sizeof (version));
   6.200 +	if (read_len != sizeof (version)) {
   6.201 +		warnx("failed to read version from input file");
   6.202 +		if (read_len < 0) {
   6.203 +			openssl_warn();
   6.204 +		}
   6.205 +		retval = -1;
   6.206 +		goto out;
   6.207 +	}
   6.208 +	version = htonl(version);
   6.209 +	if (version != SENCRYPT_FORMAT_VERSION) {
   6.210 +		warnx("unknown format version %d", version);
   6.211 +		retval = -1;
   6.212 +		goto out;
   6.213 +	}
   6.214 +
   6.215 +	read_len = BIO_read(bio_in, iterations, sizeof (*iterations));
   6.216 +	if (read_len != sizeof (*iterations)) {
   6.217 +		warnx("failed to read iterations from input file");
   6.218 +		if (read_len < 0) {
   6.219 +			openssl_warn();
   6.220 +		}
   6.221 +		retval = -1;
   6.222 +		goto out;
   6.223 +	}
   6.224 +	*iterations = htonl(*iterations);
   6.225 +	if ((*iterations == 0) || ((sizeof (int) <= sizeof (uint32_t)) &&
   6.226 +	    (*iterations > INT_MAX))) {
   6.227 +		warnx("invalid number of iterations");
   6.228 +		retval = -1;
   6.229 +		goto out;
   6.230 +	}
   6.231 +
   6.232 +	if (iv_len > 0) {
   6.233 +		read_len = BIO_read(bio_in, iv, iv_len);
   6.234 +		if (read_len != iv_len) {
   6.235 +			warnx("failed to read IV from input file");
   6.236 +			if (read_len < 0) {
   6.237 +				openssl_warn();
   6.238 +			}
   6.239 +			retval = -1;
   6.240 +			goto out;
   6.241 +		}
   6.242 +	}
   6.243 +
   6.244 +	read_len = BIO_read(bio_in, salt, salt_len);
   6.245 +	if (read_len != salt_len) {
   6.246 +		warnx("failed to read salt from input file");
   6.247 +		if (read_len < 0) {
   6.248 +			openssl_warn();
   6.249 +		}
   6.250 +		retval = -1;
   6.251 +		goto out;
   6.252 +	}
   6.253 +
   6.254 +out:
   6.255 +	return (retval);
   6.256 +}
   6.257 +
   6.258 +static int
   6.259 +sencrypt(const EVP_CIPHER *cipher, BIO *bio_in, BIO *bio_out,
   6.260 +    const unsigned char *key, size_t key_len, const unsigned char *iv,
   6.261 +    const unsigned char *salt)
   6.262 +{
   6.263 +	int		retval = 0;
   6.264 +	uint32_t	version;
   6.265 +	uint32_t	iterations;
   6.266 +	int		iv_len;
   6.267 +	int		write_len;
   6.268 +	int		read_len;
   6.269 +	BIO		*bio_cipher = NULL;
   6.270 +	char		*buf = NULL;
   6.271 +	EVP_CIPHER_CTX	*cipher_ctx;
   6.272 +
   6.273 +	/* set up cipher filter */
   6.274 +	bio_cipher = BIO_new(BIO_f_cipher());
   6.275 +	BIO_set_cipher(bio_cipher, cipher, NULL, NULL, 1);
   6.276 +	BIO_get_cipher_ctx(bio_cipher, &cipher_ctx);
   6.277 +	if (EVP_CIPHER_CTX_set_key_length(cipher_ctx, (int)key_len) != 1) {
   6.278 +		warnx("failed to set key length");
   6.279 +		openssl_warn();
   6.280 +		retval = 1;
   6.281 +		goto out;
   6.282 +	}
   6.283 +	if (EVP_CipherInit_ex(cipher_ctx, NULL, NULL, key, iv, 1) != 1) {
   6.284 +		warnx("failed to initialize cipher");
   6.285 +		openssl_warn();
   6.286 +		retval = 1;
   6.287 +		goto out;
   6.288 +	}
   6.289 +	BIO_push(bio_cipher, bio_out);
   6.290 +
   6.291 +	/* write header */
   6.292 +	version = htonl(SENCRYPT_FORMAT_VERSION);
   6.293 +	write_len = BIO_write(bio_out, &version, sizeof (version));
   6.294 +	if (write_len != sizeof (version)) {
   6.295 +		warnx("failed to write version to output file");
   6.296 +		if (write_len < 0) {
   6.297 +			openssl_warn();
   6.298 +		}
   6.299 +		retval = 1;
   6.300 +		goto out;
   6.301 +	}
   6.302 +
   6.303 +	iterations = htonl(PBKDF2_ITERATIONS);
   6.304 +	write_len = BIO_write(bio_out, &iterations, sizeof (iterations));
   6.305 +	if (write_len != sizeof (iterations)) {
   6.306 +		warnx("failed to write iterations to output file");
   6.307 +		if (write_len < 0) {
   6.308 +			openssl_warn();
   6.309 +		}
   6.310 +		retval = 1;
   6.311 +		goto out;
   6.312 +	}
   6.313 +
   6.314 +	iv_len = EVP_CIPHER_iv_length(cipher);
   6.315 +	if (iv_len > 0) {
   6.316 +		write_len = BIO_write(bio_out, iv, iv_len);
   6.317 +		if (write_len != iv_len) {
   6.318 +			warnx("failed to write IV to output file");
   6.319 +			if (write_len < 0) {
   6.320 +				openssl_warn();
   6.321 +			}
   6.322 +			retval = 1;
   6.323 +			goto out;
   6.324 +		}
   6.325 +	}
   6.326 +
   6.327 +	write_len = BIO_write(bio_out, salt, SALT_LEN);
   6.328 +	if (write_len != SALT_LEN) {
   6.329 +		warnx("failed to write salt to output file");
   6.330 +		if (write_len < 0) {
   6.331 +			openssl_warn();
   6.332 +		}
   6.333 +		retval = 1;
   6.334 +		goto out;
   6.335 +	}
   6.336 +
   6.337 +	if (BIO_flush(bio_out) < 1) {
   6.338 +		warnx("failed to flush output file");
   6.339 +		openssl_warn();
   6.340 +		retval = 1;
   6.341 +		goto out;
   6.342 +	}
   6.343 +
   6.344 +	buf = malloc(BUFFER_SIZE);
   6.345 +	if (buf == NULL) {
   6.346 +		warn(NULL);
   6.347 +		retval = 1;
   6.348 +		goto out;
   6.349 +	}
   6.350 +
   6.351 +	/* encrypt data */
   6.352 +	while ((read_len = BIO_read(bio_in, buf, BUFFER_SIZE)) > 0) {
   6.353 +		if ((write_len = BIO_write(bio_cipher, buf, read_len)) !=
   6.354 +		    read_len) {
   6.355 +			warnx("failed to write to output file");
   6.356 +			if (write_len < 0) {
   6.357 +				openssl_warn();
   6.358 +			}
   6.359 +			retval = 1;
   6.360 +			goto out;
   6.361 +		}
   6.362 +	}
   6.363 +	if (read_len < 0) {
   6.364 +		warnx("failed to read from input file");
   6.365 +		openssl_warn();
   6.366 +		retval = 1;
   6.367 +		goto out;
   6.368 +	}
   6.369 +
   6.370 +	if (BIO_flush(bio_cipher) < 1) {
   6.371 +		warnx("failed to flush output file");
   6.372 +		openssl_warn();
   6.373 +		retval = 1;
   6.374 +		goto out;
   6.375 +	}
   6.376 +
   6.377 +out:
   6.378 +	free(buf);
   6.379 +
   6.380 +	if (bio_cipher != NULL) {
   6.381 +		BIO_pop(bio_cipher);
   6.382 +		BIO_free(bio_cipher);
   6.383 +	}
   6.384 +
   6.385 +	return (retval);
   6.386 +}
   6.387 +
   6.388 +static int
   6.389 +sdecrypt(const EVP_CIPHER *cipher, BIO *bio_in, BIO *bio_out,
   6.390 +    const unsigned char *key, size_t key_len, const unsigned char *iv)
   6.391 +{
   6.392 +	int		read_len;
   6.393 +	BIO		*bio_cipher = NULL;
   6.394 +	int		write_len;
   6.395 +	char		*buf = NULL;
   6.396 +	EVP_CIPHER_CTX	*cipher_ctx;
   6.397 +	int		retval = 0;
   6.398 +
   6.399 +	buf = malloc(BUFFER_SIZE);
   6.400 +	if (buf == NULL) {
   6.401 +		warn(NULL);
   6.402 +		retval = 1;
   6.403 +		goto out;
   6.404 +	}
   6.405 +
   6.406 +	/* set up cipher filter */
   6.407 +	bio_cipher = BIO_new(BIO_f_cipher());
   6.408 +	BIO_set_cipher(bio_cipher, cipher, NULL, NULL, 0);
   6.409 +	BIO_get_cipher_ctx(bio_cipher, &cipher_ctx);
   6.410 +	if (EVP_CIPHER_CTX_set_key_length(cipher_ctx, (int)key_len) != 1) {
   6.411 +		warnx("failed to set key length");
   6.412 +		openssl_warn();
   6.413 +		retval = 1;
   6.414 +		goto out;
   6.415 +	}
   6.416 +	if (EVP_CipherInit_ex(cipher_ctx, NULL, NULL, key, iv, 0) != 1) {
   6.417 +		warnx("failed to initialize cipher");
   6.418 +		openssl_warn();
   6.419 +		retval = 1;
   6.420 +		goto out;
   6.421 +	}
   6.422 +	BIO_push(bio_cipher, bio_in);
   6.423 +
   6.424 +	/* decrypt data */
   6.425 +	while ((read_len = BIO_read(bio_cipher, buf, BUFFER_SIZE)) > 0) {
   6.426 +		if ((write_len = BIO_write(bio_out, buf, read_len)) !=
   6.427 +		    read_len) {
   6.428 +			warnx("failed to write to to output file");
   6.429 +			if (write_len < 0) {
   6.430 +				openssl_warn();
   6.431 +			}
   6.432 +			retval = 1;
   6.433 +			goto out;
   6.434 +		}
   6.435 +	}
   6.436 +	if (read_len < 0) {
   6.437 +		warnx("failed to read from input file");
   6.438 +		openssl_warn();
   6.439 +		retval = 1;
   6.440 +		goto out;
   6.441 +	}
   6.442 +
   6.443 +	if (BIO_flush(bio_out) < 1) {
   6.444 +		warnx("failed to flush output file");
   6.445 +		openssl_warn();
   6.446 +		retval = 1;
   6.447 +		goto out;
   6.448 +	}
   6.449 +
   6.450 +	if (BIO_get_cipher_status(bio_cipher) == 0) {
   6.451 +		warnx("decryption failed");
   6.452 +		openssl_warn();
   6.453 +		retval = 1;
   6.454 +		goto out;
   6.455 +	}
   6.456 +
   6.457 +out:
   6.458 +	free(buf);
   6.459 +
   6.460 +	if (bio_cipher != NULL) {
   6.461 +		BIO_pop(bio_cipher);
   6.462 +		BIO_free(bio_cipher);
   6.463 +	}
   6.464 +
   6.465 +	return (retval);
   6.466 +}
   6.467 +
   6.468 +static void
   6.469 +list_algorithms(void)
   6.470 +{
   6.471 +	printf("Algorithm       Keysize:  Min   Max (bits)\n"
   6.472 +	    "------------------------------------------\n");
   6.473 +	printf("%-15s         %5u %5u\n", "aes", 128, 256);
   6.474 +	printf("%-15s         %5u %5u\n", "arcfour", 8,
   6.475 +	    EVP_MAX_KEY_LENGTH * 8);
   6.476 +	printf("%-15s         %5u %5u\n", "des", 64, 64);
   6.477 +	printf("%-15s         %5u %5u\n", "3des", 192, 192);
   6.478 +}
   6.479 +
   6.480 +static void
   6.481 +usage(int cmd)
   6.482 +{
   6.483 +	if (cmd == CMD_SENCRYPT) {
   6.484 +		fprintf(stderr, "usage: sencrypt -l | [-v] -a algorithm "
   6.485 +		    "[-k key_file] [-i input_file] [-o output_file]\n");
   6.486 +	} else if (cmd == CMD_SDECRYPT) {
   6.487 +		fprintf(stderr, "usage: sdecrypt -l | [-v] -a algorithm "
   6.488 +		    "[-k key_file] [-i input_file] [-o output_file]\n");
   6.489 +	}
   6.490 +}
   6.491 +
   6.492 +int
   6.493 +main(int argc, char *argv[])
   6.494 +{
   6.495 +	char		*progname;
   6.496 +	int		cmd;
   6.497 +	int		c;
   6.498 +	bool		aflag = false;
   6.499 +	char		*algo_name = NULL;
   6.500 +	bool		is_algo_rc4 = false;
   6.501 +	bool		iflag = false;
   6.502 +	char		*in_filename = NULL;
   6.503 +	bool		kflag = false;
   6.504 +	char		*key_filename = NULL;
   6.505 +	bool		lflag = false;
   6.506 +	bool		oflag = false;
   6.507 +	char		*out_filename = NULL;
   6.508 +	bool		vflag = false;
   6.509 +	bool		errflag = false;
   6.510 +	unsigned char	key[EVP_MAX_KEY_LENGTH];
   6.511 +	size_t		key_len = 0;
   6.512 +	size_t		key_file_len;
   6.513 +	const EVP_CIPHER	*cipher;
   6.514 +	BIO		*bio_in = NULL;
   6.515 +	uint32_t	iterations = PBKDF2_ITERATIONS;
   6.516 +	unsigned char	iv[EVP_MAX_IV_LENGTH];
   6.517 +	unsigned char	salt[SALT_LEN];
   6.518 +	BIO		*bio_out = NULL;
   6.519 +	int		need_tmpfile = 0;
   6.520 +	FILE		*fp_in;
   6.521 +	struct stat	statbuf_in;
   6.522 +	struct stat	statbuf_out;
   6.523 +	int		fd_tmp = -1;
   6.524 +	FILE		*fp_tmp = NULL;
   6.525 +	char		*out_filename_tmp = NULL;
   6.526 +	char		*out_dir = NULL;
   6.527 +	char		*tmp_filename = NULL;
   6.528 +	int		len;
   6.529 +	mode_t		old_mode;
   6.530 +	char		pwdata[MAX(MAX_PASSWORD_LEN, EVP_MAX_KEY_LENGTH)];
   6.531 +	size_t		pwdata_len = 0;
   6.532 +	int		status = EXIT_SUCCESS;
   6.533 +
   6.534 +	/* initialize OpenSSL */
   6.535 +	OpenSSL_add_all_algorithms();
   6.536 +	ERR_load_crypto_strings();
   6.537 +	OPENSSL_config(NULL);
   6.538 +
   6.539 +	progname = strrchr(argv[0], '/');
   6.540 +	progname = (progname != NULL) ? progname + 1 : argv[0];
   6.541 +	if ((strcmp(progname, "sencrypt") == 0) ||
   6.542 +	    (strcmp(progname, "encrypt") == 0)) {
   6.543 +		cmd = CMD_SENCRYPT;
   6.544 +	} else if ((strcmp(progname, "sdecrypt") == 0) ||
   6.545 +	    (strcmp(progname, "decrypt") == 0)) {
   6.546 +		cmd = CMD_SDECRYPT;
   6.547 +	} else {
   6.548 +		fprintf(stderr, "invalid command name");
   6.549 +		status = EXIT_FAILURE;
   6.550 +		goto out;
   6.551 +	}
   6.552 +
   6.553 +	while (!errflag && (c = getopt(argc, argv, "a:i:k:lo:v")) != -1) {
   6.554 +		switch (c) {
   6.555 +		case 'a':
   6.556 +			aflag = true;
   6.557 +			algo_name = optarg;
   6.558 +			is_algo_rc4 = (strcmp(algo_name, "arcfour") == 0);
   6.559 +			break;
   6.560 +		case 'i':
   6.561 +			iflag = true;
   6.562 +			in_filename = optarg;
   6.563 +			break;
   6.564 +		case 'k':
   6.565 +			kflag = true;
   6.566 +			key_filename = optarg;
   6.567 +			break;
   6.568 +		case 'l':
   6.569 +			lflag = true;
   6.570 +			break;
   6.571 +		case 'o':
   6.572 +			oflag = true;
   6.573 +			out_filename = optarg;
   6.574 +			break;
   6.575 +		case 'v':
   6.576 +			vflag = true;
   6.577 +			break;
   6.578 +		default:
   6.579 +			errflag = true;
   6.580 +		}
   6.581 +	}
   6.582 +	if (errflag || (!lflag && !aflag) || (lflag && aflag) ||
   6.583 +	    (argc > optind)) {
   6.584 +		usage(cmd);
   6.585 +		status = EXIT_USAGE;
   6.586 +		goto out;
   6.587 +	}
   6.588 +
   6.589 +	if (lflag) {
   6.590 +		list_algorithms();
   6.591 +		goto out;
   6.592 +	}
   6.593 +
   6.594 +	if (kflag) {
   6.595 +		key_file_len = read_keyfile(key_filename, key,
   6.596 +		    (off_t)sizeof (key));
   6.597 +		if (key_file_len < 1) {
   6.598 +			status = EXIT_FAILURE;
   6.599 +			goto out;
   6.600 +		}
   6.601 +		key_len = key_file_len;
   6.602 +	} else {
   6.603 +		if (EVP_read_pw_string(pwdata, sizeof (pwdata), "Enter key:",
   6.604 +		    (cmd == CMD_SENCRYPT) ? 1 : 0) != 0) {
   6.605 +			warnx("could not read passphrase");
   6.606 +			openssl_warn();
   6.607 +			status = EXIT_FAILURE;
   6.608 +			goto out;
   6.609 +		}
   6.610 +		pwdata_len = strlen(pwdata);
   6.611 +		if (pwdata_len < 1) {
   6.612 +			warnx("invalid passphrase");
   6.613 +			status = EXIT_FAILURE;
   6.614 +			goto out;
   6.615 +		}
   6.616 +	}
   6.617 +
   6.618 +	/* the cipher is determined based on name and length of the key file */
   6.619 +	if (find_algorithm(algo_name, &cipher, &key_len) == -1) {
   6.620 +		status = EXIT_FAILURE;
   6.621 +		goto out;
   6.622 +	}
   6.623 +
   6.624 +	if (iflag) {
   6.625 +		bio_in = BIO_new_file(in_filename, "r");
   6.626 +	} else {
   6.627 +		bio_in = BIO_new_fp(stdin, BIO_NOCLOSE);
   6.628 +	}
   6.629 +	if (bio_in == NULL) {
   6.630 +		warnx("could not open input file");
   6.631 +		openssl_warn();
   6.632 +		status = EXIT_FAILURE;
   6.633 +		goto out;
   6.634 +	}
   6.635 +
   6.636 +	if (cmd == CMD_SENCRYPT) {
   6.637 +		/* generate random salt and IV */
   6.638 +		if ((RAND_bytes(salt, sizeof (salt)) == 0) ||
   6.639 +		    (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) == 0)) {
   6.640 +			/* not enough entropy or unknown error */
   6.641 +			warnx("failed to generate random data");
   6.642 +			status = EXIT_FAILURE;
   6.643 +			goto out;
   6.644 +		}
   6.645 +	} else {
   6.646 +		read_header(bio_in, &iterations, iv,
   6.647 +		    EVP_CIPHER_iv_length(cipher), salt, (int)sizeof (salt));
   6.648 +	}
   6.649 +
   6.650 +	/*
   6.651 +	 * if no keyfile was given or the RC4 cipher is used, derive the key
   6.652 +	 * from the password and salt
   6.653 +	 */
   6.654 +	if (kflag && is_algo_rc4) {
   6.655 +		memcpy(pwdata, key, key_file_len);
   6.656 +		pwdata_len = key_file_len;
   6.657 +	}
   6.658 +	if (!kflag || is_algo_rc4) {
   6.659 +		if (PKCS5_PBKDF2_HMAC_SHA1(pwdata, (int)pwdata_len, salt,
   6.660 +		    sizeof (salt), (int)iterations, (int)key_len, key) == 0) {
   6.661 +			warnx("failed to generate key");
   6.662 +			status = EXIT_FAILURE;
   6.663 +			goto out;
   6.664 +		}
   6.665 +	}
   6.666 +
   6.667 +	if (oflag) {
   6.668 +		/*
   6.669 +		 * if input and output files are identical, create and write the
   6.670 +		 * output to a temporary file for the output which is then
   6.671 +		 * renamed to out_filename
   6.672 +		 */
   6.673 +		if (iflag) {
   6.674 +			BIO_get_fp(bio_in, &fp_in);
   6.675 +			if (fstat(fileno(fp_in), &statbuf_in) == -1) {
   6.676 +				warn("could not stat input file");
   6.677 +				status = EXIT_FAILURE;
   6.678 +				goto out;
   6.679 +			}
   6.680 +			if (stat(out_filename, &statbuf_out) == -1) {
   6.681 +				if (errno != ENOENT) {
   6.682 +					warn("could not stat output file");
   6.683 +					status = EXIT_FAILURE;
   6.684 +					goto out;
   6.685 +				}
   6.686 +			} else if ((statbuf_in.st_ino == statbuf_out.st_ino) &&
   6.687 +				    (statbuf_in.st_dev == statbuf_out.st_dev)) {
   6.688 +				need_tmpfile = 1;
   6.689 +			}
   6.690 +		}
   6.691 +
   6.692 +		if (need_tmpfile) {
   6.693 +			out_filename_tmp = strdup(out_filename);
   6.694 +			if (out_filename_tmp == NULL) {
   6.695 +				warn(NULL);
   6.696 +				status = EXIT_FAILURE;
   6.697 +				goto out;
   6.698 +			}
   6.699 +			out_dir = dirname(out_filename_tmp);
   6.700 +			len = snprintf(NULL, 0, "%s/sencryptXXXXXX", out_dir);
   6.701 +			if (len < 0) {
   6.702 +				warn(NULL);
   6.703 +				status = EXIT_FAILURE;
   6.704 +				goto out;
   6.705 +			}
   6.706 +			tmp_filename = malloc((size_t)len + 1);
   6.707 +			if (tmp_filename == NULL) {
   6.708 +				warn(NULL);
   6.709 +				status = EXIT_FAILURE;
   6.710 +				goto out;
   6.711 +			}
   6.712 +			if (snprintf(tmp_filename, (size_t)len + 1,
   6.713 +			    "%s/sencryptXXXXXX", out_dir) != len) {
   6.714 +				warn(NULL);
   6.715 +				status = EXIT_FAILURE;
   6.716 +				goto out;
   6.717 +			}
   6.718 +			old_mode = umask(077);
   6.719 +			fd_tmp = mkstemp(tmp_filename);
   6.720 +			umask(old_mode);
   6.721 +			if (fd_tmp == -1) {
   6.722 +				warn("could not create temporary file");
   6.723 +				status = EXIT_FAILURE;
   6.724 +				goto out;
   6.725 +			}
   6.726 +			fp_tmp = fdopen(fd_tmp, "w");
   6.727 +			if (fp_tmp == NULL) {
   6.728 +				warn("could not open temporary file");
   6.729 +				status = EXIT_FAILURE;
   6.730 +				goto out;
   6.731 +			}
   6.732 +			fd_tmp = -1;
   6.733 +			bio_out = BIO_new_fp(fp_tmp, BIO_CLOSE);
   6.734 +			if (bio_out == NULL) {
   6.735 +				warnx("could not open temporary file");
   6.736 +				openssl_warn();
   6.737 +				status = EXIT_FAILURE;
   6.738 +				goto out;
   6.739 +			}
   6.740 +			fp_tmp = NULL;
   6.741 +		} else {
   6.742 +			old_mode = umask(077);
   6.743 +			bio_out = BIO_new_file(out_filename, "w");
   6.744 +			umask(old_mode);
   6.745 +			if (bio_out == NULL) {
   6.746 +				warnx("could not open output file");
   6.747 +				openssl_warn();
   6.748 +				status = EXIT_FAILURE;
   6.749 +				goto out;
   6.750 +			}
   6.751 +		}
   6.752 +	} else {
   6.753 +		bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
   6.754 +		if (bio_out == NULL) {
   6.755 +			warnx("could not open output file");
   6.756 +			openssl_warn();
   6.757 +			status = EXIT_FAILURE;
   6.758 +			goto out;
   6.759 +		}
   6.760 +	}
   6.761 +
   6.762 +	if (cmd == CMD_SENCRYPT) {
   6.763 +		if (sencrypt(cipher, bio_in, bio_out, key, key_len,
   6.764 +		    iv, salt) == -1) {
   6.765 +			status = EXIT_FAILURE;
   6.766 +		}
   6.767 +	} else {
   6.768 +		if (sdecrypt(cipher, bio_in, bio_out, key, key_len,
   6.769 +		    iv) == -1) {
   6.770 +			status = EXIT_FAILURE;
   6.771 +		}
   6.772 +	}
   6.773 +
   6.774 +out:
   6.775 +	OPENSSL_cleanse(pwdata, pwdata_len);
   6.776 +	OPENSSL_cleanse(key, key_len);
   6.777 +
   6.778 +	if (fd_tmp != -1) {
   6.779 +		close(fd_tmp);
   6.780 +	}
   6.781 +
   6.782 +	if (fp_tmp != NULL) {
   6.783 +		fclose(fp_tmp);
   6.784 +	}
   6.785 +
   6.786 +	if (bio_in != NULL) {
   6.787 +		BIO_free_all(bio_in);
   6.788 +	}
   6.789 +
   6.790 +	if (bio_out != NULL) {
   6.791 +		BIO_free_all(bio_out);
   6.792 +
   6.793 +		if (status == 0) {
   6.794 +			if (need_tmpfile) {
   6.795 +				if (rename(tmp_filename, out_filename) == -1) {
   6.796 +					warn("could not create output file");
   6.797 +					status = EXIT_FAILURE;
   6.798 +					unlink(tmp_filename);
   6.799 +				}
   6.800 +			}
   6.801 +		} else {
   6.802 +			if (need_tmpfile) {
   6.803 +				unlink(tmp_filename);
   6.804 +			} else if (oflag) {
   6.805 +				unlink(out_filename);
   6.806 +			}
   6.807 +		}
   6.808 +	}
   6.809 +
   6.810 +	free(out_filename_tmp);
   6.811 +	free(tmp_filename);
   6.812 +
   6.813 +	EVP_cleanup();
   6.814 +	ERR_free_strings();
   6.815 +	CONF_modules_free();
   6.816 +
   6.817 +	exit(status);
   6.818 +}