2010-12-15 23:45:21 +01:00
|
|
|
/*
|
2021-02-16 04:20:06 +01:00
|
|
|
Copyright (C) 2006-2016,2021 Con Kolivas
|
2011-03-21 11:02:05 +01:00
|
|
|
Copyright (C) 2011 Serge Belyshev
|
2011-02-21 06:11:59 +01:00
|
|
|
Copyright (C) 2008, 2011 Peter Hyman
|
2010-12-15 23:45:21 +01:00
|
|
|
Copyright (C) 1998 Andrew Tridgell
|
2010-11-04 11:14:55 +01:00
|
|
|
|
2010-03-29 01:07:08 +02:00
|
|
|
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 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
2010-12-15 23:45:21 +01:00
|
|
|
|
2010-03-29 01:07:08 +02:00
|
|
|
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.
|
2010-12-15 23:45:21 +01:00
|
|
|
|
2010-03-29 01:07:08 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
2010-12-15 23:45:21 +01:00
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2010-03-29 01:07:08 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Utilities used in rzip
|
|
|
|
|
|
|
|
|
|
tridge, June 1996
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Realloc removed
|
|
|
|
|
* Functions added
|
|
|
|
|
* read_config()
|
|
|
|
|
* Peter Hyman, December 2008
|
|
|
|
|
*/
|
|
|
|
|
|
2011-03-08 22:34:44 +01:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-03-08 22:37:26 +01:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
2011-03-15 06:32:32 +01:00
|
|
|
#include <termios.h>
|
2011-03-08 22:37:26 +01:00
|
|
|
|
|
|
|
|
#ifdef _SC_PAGE_SIZE
|
|
|
|
|
# define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
|
|
|
|
|
#else
|
|
|
|
|
# define PAGE_SIZE (4096)
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-03-15 02:56:23 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
2011-03-18 00:22:58 +01:00
|
|
|
#include <sys/mman.h>
|
2011-03-15 02:56:23 +01:00
|
|
|
#include <fcntl.h>
|
2011-03-08 22:37:26 +01:00
|
|
|
#include "lrzip_private.h"
|
2011-03-21 10:54:53 +01:00
|
|
|
#include "util.h"
|
2011-03-18 00:22:58 +01:00
|
|
|
#include "sha4.h"
|
|
|
|
|
#include "aes.h"
|
2011-08-11 11:44:16 +02:00
|
|
|
#ifdef HAVE_CTYPE_H
|
|
|
|
|
# include <ctype.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Macros for testing parameters */
|
|
|
|
|
#define isparameter( parmstring, value ) (!strcasecmp( parmstring, value ))
|
|
|
|
|
#define iscaseparameter( parmvalue, value ) (!strcmp( parmvalue, value ))
|
2011-03-18 00:22:58 +01:00
|
|
|
|
2011-08-11 09:06:32 +02:00
|
|
|
void register_infile(rzip_control *control, const char *name, char delete)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
2011-08-11 09:06:32 +02:00
|
|
|
control->util_infile = name;
|
|
|
|
|
control->delete_infile = delete;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-11 09:06:32 +02:00
|
|
|
void register_outfile(rzip_control *control, const char *name, char delete)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
2011-08-11 09:06:32 +02:00
|
|
|
control->util_outfile = name;
|
|
|
|
|
control->delete_outfile = delete;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-11 09:06:32 +02:00
|
|
|
void register_outputfile(rzip_control *control, FILE *f)
|
2011-03-08 22:32:14 +01:00
|
|
|
{
|
2011-08-11 09:06:32 +02:00
|
|
|
control->outputfile = f;
|
2011-03-08 22:32:14 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-11 09:06:32 +02:00
|
|
|
void unlink_files(rzip_control *control)
|
2011-02-21 04:17:05 +01:00
|
|
|
{
|
|
|
|
|
/* Delete temporary files generated for testing or faking stdio */
|
2011-08-11 09:06:32 +02:00
|
|
|
if (control->util_outfile && control->delete_outfile)
|
|
|
|
|
unlink(control->util_outfile);
|
2011-02-21 04:17:05 +01:00
|
|
|
|
2011-08-11 09:06:32 +02:00
|
|
|
if (control->util_infile && control->delete_infile)
|
|
|
|
|
unlink(control->util_infile);
|
2011-02-21 04:17:05 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
void fatal_exit(rzip_control *control)
|
2011-02-21 06:11:59 +01:00
|
|
|
{
|
2011-03-15 06:32:32 +01:00
|
|
|
struct termios termios_p;
|
|
|
|
|
|
|
|
|
|
/* Make sure we haven't died after disabling stdin echo */
|
|
|
|
|
tcgetattr(fileno(stdin), &termios_p);
|
|
|
|
|
termios_p.c_lflag |= ECHO;
|
|
|
|
|
tcsetattr(fileno(stdin), 0, &termios_p);
|
|
|
|
|
|
2011-08-11 09:06:32 +02:00
|
|
|
unlink_files(control);
|
2021-02-15 07:13:57 +01:00
|
|
|
if (!STDOUT && !TEST_ONLY && control->outfile) {
|
|
|
|
|
if (!KEEP_BROKEN) {
|
|
|
|
|
print_verbose("Deleting broken file %s\n", control->outfile);
|
|
|
|
|
unlink(control->outfile);
|
|
|
|
|
} else
|
|
|
|
|
print_verbose("Keeping broken file %s as requested\n", control->outfile);
|
|
|
|
|
}
|
2011-08-11 09:06:32 +02:00
|
|
|
fprintf(control->outputfile, "Fatal error - exiting\n");
|
|
|
|
|
fflush(control->outputfile);
|
2011-08-12 08:43:42 +02:00
|
|
|
exit(1);
|
2011-02-21 04:51:20 +01:00
|
|
|
}
|
|
|
|
|
|
2011-08-11 06:57:43 +02:00
|
|
|
void setup_overhead(rzip_control *control)
|
|
|
|
|
{
|
|
|
|
|
/* Work out the compression overhead per compression thread for the
|
|
|
|
|
* compression back-ends that need a lot of ram */
|
|
|
|
|
if (LZMA_COMPRESS) {
|
2015-03-10 08:33:10 +01:00
|
|
|
int level = control->compression_level * 7 / 9;
|
|
|
|
|
|
|
|
|
|
if (!level)
|
|
|
|
|
level = 1;
|
2011-08-11 06:57:43 +02:00
|
|
|
i64 dictsize = (level <= 5 ? (1 << (level * 2 + 14)) :
|
|
|
|
|
(level == 6 ? (1 << 25) : (1 << 26)));
|
|
|
|
|
|
2019-11-25 14:31:29 +01:00
|
|
|
control->overhead = (dictsize * 23 / 2) + (6 * 1024 * 1024) + 16384;
|
|
|
|
|
/* LZMA spec shows memory requirements as 6MB, not 4MB and state size
|
|
|
|
|
* where default is 16KB */
|
2011-08-11 06:57:43 +02:00
|
|
|
} else if (ZPAQ_COMPRESS)
|
|
|
|
|
control->overhead = 112 * 1024 * 1024;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-11 06:52:59 +02:00
|
|
|
void setup_ram(rzip_control *control)
|
|
|
|
|
{
|
|
|
|
|
/* Use less ram when using STDOUT to store the temporary output file. */
|
|
|
|
|
if (STDOUT && ((STDIN && DECOMPRESS) || !(DECOMPRESS || TEST_ONLY)))
|
2013-09-01 16:07:30 +02:00
|
|
|
control->maxram = control->ramsize / 6;
|
2011-08-11 06:52:59 +02:00
|
|
|
else
|
|
|
|
|
control->maxram = control->ramsize / 3;
|
|
|
|
|
if (BITS32) {
|
|
|
|
|
/* Decrease usable ram size on 32 bits due to kernel /
|
|
|
|
|
* userspace split. Cannot allocate larger than a 1
|
|
|
|
|
* gigabyte chunk due to 32 bit signed long being
|
|
|
|
|
* used in alloc, and at most 3GB can be malloced, and
|
|
|
|
|
* 2/3 of that makes for a total of 2GB to be split
|
|
|
|
|
* into thirds.
|
|
|
|
|
*/
|
|
|
|
|
control->usable_ram = MAX(control->ramsize - 900000000ll, 900000000ll);
|
|
|
|
|
control->maxram = MIN(control->maxram, control->usable_ram);
|
|
|
|
|
control->maxram = MIN(control->maxram, one_g * 2 / 3);
|
|
|
|
|
} else
|
|
|
|
|
control->usable_ram = control->maxram;
|
|
|
|
|
round_to_page(&control->maxram);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 14:49:50 +01:00
|
|
|
void round_to_page(i64 *size)
|
|
|
|
|
{
|
2011-03-08 22:32:14 +01:00
|
|
|
*size -= *size % PAGE_SIZE;
|
2011-02-21 14:49:50 +01:00
|
|
|
if (unlikely(!*size))
|
2011-03-08 22:32:14 +01:00
|
|
|
*size = PAGE_SIZE;
|
2011-02-21 14:49:50 +01:00
|
|
|
}
|
2011-03-15 02:56:23 +01:00
|
|
|
|
2013-09-14 03:41:57 +02:00
|
|
|
size_t round_up_page(rzip_control *control, size_t len)
|
|
|
|
|
{
|
|
|
|
|
int rem = len % control->page_size;
|
|
|
|
|
|
|
|
|
|
if (rem)
|
|
|
|
|
len += control->page_size - rem;
|
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool get_rand(rzip_control *control, uchar *buf, int len)
|
2011-03-15 02:56:23 +01:00
|
|
|
{
|
|
|
|
|
int fd, i;
|
|
|
|
|
|
|
|
|
|
fd = open("/dev/urandom", O_RDONLY);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
buf[i] = (uchar)random();
|
|
|
|
|
} else {
|
|
|
|
|
if (unlikely(read(fd, buf, len) != len))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to read fd in get_rand\n"), false);
|
2011-03-15 02:56:23 +01:00
|
|
|
if (unlikely(close(fd)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to close fd in get_rand\n"), false);
|
2011-03-15 02:56:23 +01:00
|
|
|
}
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2013-09-14 03:41:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool read_config(rzip_control *control)
|
2011-08-11 11:44:16 +02:00
|
|
|
{
|
|
|
|
|
/* check for lrzip.conf in ., $HOME/.lrzip and /etc/lrzip */
|
2011-08-12 08:43:42 +02:00
|
|
|
char *HOME, homeconf[255];
|
2011-08-11 11:44:16 +02:00
|
|
|
char *parametervalue;
|
|
|
|
|
char *parameter;
|
2011-08-12 08:43:42 +02:00
|
|
|
char line[255];
|
2011-08-11 11:44:16 +02:00
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
|
|
fp = fopen("lrzip.conf", "r");
|
|
|
|
|
if (fp)
|
|
|
|
|
fprintf(control->msgout, "Using configuration file ./lrzip.conf\n");
|
|
|
|
|
if (fp == NULL) {
|
|
|
|
|
HOME=getenv("HOME");
|
|
|
|
|
if (HOME) {
|
2011-08-12 08:43:42 +02:00
|
|
|
snprintf(homeconf, sizeof(homeconf), "%s/.lrzip/lrzip.conf", HOME);
|
2011-08-11 11:44:16 +02:00
|
|
|
fp = fopen(homeconf, "r");
|
|
|
|
|
if (fp)
|
|
|
|
|
fprintf(control->msgout, "Using configuration file %s\n", homeconf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-06 14:21:32 +01:00
|
|
|
if (fp == NULL) {
|
|
|
|
|
fp = fopen("/etc/lrzip/lrzip.conf", "r");
|
|
|
|
|
if (fp)
|
|
|
|
|
fprintf(control->msgout, "Using configuration file /etc/lrzip/lrzip.conf\n");
|
|
|
|
|
}
|
2012-03-07 12:04:24 +01:00
|
|
|
if (fp == NULL)
|
2019-06-19 12:36:21 +02:00
|
|
|
return false;
|
2011-08-11 11:44:16 +02:00
|
|
|
|
|
|
|
|
/* if we get here, we have a file. read until no more. */
|
|
|
|
|
|
|
|
|
|
while ((fgets(line, 255, fp)) != NULL) {
|
|
|
|
|
if (strlen(line))
|
|
|
|
|
line[strlen(line) - 1] = '\0';
|
|
|
|
|
parameter = strtok(line, " =");
|
|
|
|
|
if (parameter == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
/* skip if whitespace or # */
|
|
|
|
|
if (isspace(*parameter))
|
|
|
|
|
continue;
|
|
|
|
|
if (*parameter == '#')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
parametervalue = strtok(NULL, " =");
|
|
|
|
|
if (parametervalue == NULL)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* have valid parameter line, now assign to control */
|
|
|
|
|
|
|
|
|
|
if (isparameter(parameter, "window"))
|
|
|
|
|
control->window = atoi(parametervalue);
|
|
|
|
|
else if (isparameter(parameter, "unlimited")) {
|
|
|
|
|
if (isparameter(parametervalue, "yes"))
|
|
|
|
|
control->flags |= FLAG_UNLIMITED;
|
|
|
|
|
} else if (isparameter(parameter, "compressionlevel")) {
|
|
|
|
|
control->compression_level = atoi(parametervalue);
|
|
|
|
|
if ( control->compression_level < 1 || control->compression_level > 9 )
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("CONF.FILE error. Compression Level must between 1 and 9"), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
} else if (isparameter(parameter, "compressionmethod")) {
|
|
|
|
|
/* valid are rzip, gzip, bzip2, lzo, lzma (default), and zpaq */
|
|
|
|
|
if (control->flags & FLAG_NOT_LZMA)
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("CONF.FILE error. Can only specify one compression method"), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
if (isparameter(parametervalue, "bzip2"))
|
|
|
|
|
control->flags |= FLAG_BZIP2_COMPRESS;
|
|
|
|
|
else if (isparameter(parametervalue, "gzip"))
|
|
|
|
|
control->flags |= FLAG_ZLIB_COMPRESS;
|
|
|
|
|
else if (isparameter(parametervalue, "lzo"))
|
|
|
|
|
control->flags |= FLAG_LZO_COMPRESS;
|
|
|
|
|
else if (isparameter(parametervalue, "rzip"))
|
|
|
|
|
control->flags |= FLAG_NO_COMPRESS;
|
|
|
|
|
else if (isparameter(parametervalue, "zpaq"))
|
|
|
|
|
control->flags |= FLAG_ZPAQ_COMPRESS;
|
|
|
|
|
else if (!isparameter(parametervalue, "lzma")) /* oops, not lzma! */
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("CONF.FILE error. Invalid compression method %s specified\n",parametervalue), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
} else if (isparameter(parameter, "lzotest")) {
|
|
|
|
|
/* default is yes */
|
|
|
|
|
if (isparameter(parametervalue, "no"))
|
|
|
|
|
control->flags &= ~FLAG_THRESHOLD;
|
|
|
|
|
} else if (isparameter(parameter, "hashcheck")) {
|
|
|
|
|
if (isparameter(parametervalue, "yes")) {
|
|
|
|
|
control->flags |= FLAG_CHECK;
|
|
|
|
|
control->flags |= FLAG_HASH;
|
|
|
|
|
}
|
|
|
|
|
} else if (isparameter(parameter, "showhash")) {
|
|
|
|
|
if (isparameter(parametervalue, "yes"))
|
|
|
|
|
control->flags |= FLAG_HASH;
|
|
|
|
|
} else if (isparameter(parameter, "outputdirectory")) {
|
|
|
|
|
control->outdir = malloc(strlen(parametervalue) + 2);
|
|
|
|
|
if (!control->outdir)
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Fatal Memory Error in read_config"), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
strcpy(control->outdir, parametervalue);
|
|
|
|
|
if (strcmp(parametervalue + strlen(parametervalue) - 1, "/"))
|
|
|
|
|
strcat(control->outdir, "/");
|
|
|
|
|
} else if (isparameter(parameter,"verbosity")) {
|
|
|
|
|
if (control->flags & FLAG_VERBOSE)
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("CONF.FILE error. Verbosity already defined."), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
if (isparameter(parametervalue, "yes"))
|
|
|
|
|
control->flags |= FLAG_VERBOSITY;
|
|
|
|
|
else if (isparameter(parametervalue,"max"))
|
|
|
|
|
control->flags |= FLAG_VERBOSITY_MAX;
|
|
|
|
|
else /* oops, unrecognized value */
|
|
|
|
|
print_err("lrzip.conf: Unrecognized verbosity value %s. Ignored.\n", parametervalue);
|
|
|
|
|
} else if (isparameter(parameter, "showprogress")) {
|
|
|
|
|
/* Yes by default */
|
|
|
|
|
if (isparameter(parametervalue, "NO"))
|
|
|
|
|
control->flags &= ~FLAG_SHOW_PROGRESS;
|
|
|
|
|
} else if (isparameter(parameter,"nice")) {
|
|
|
|
|
control->nice_val = atoi(parametervalue);
|
|
|
|
|
if (control->nice_val < -20 || control->nice_val > 19)
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_return(("CONF.FILE error. Nice must be between -20 and 19"), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
} else if (isparameter(parameter, "keepbroken")) {
|
|
|
|
|
if (isparameter(parametervalue, "yes" ))
|
|
|
|
|
control->flags |= FLAG_KEEP_BROKEN;
|
|
|
|
|
} else if (iscaseparameter(parameter, "DELETEFILES")) {
|
|
|
|
|
/* delete files must be case sensitive */
|
|
|
|
|
if (iscaseparameter(parametervalue, "YES"))
|
|
|
|
|
control->flags &= ~FLAG_KEEP_FILES;
|
|
|
|
|
} else if (iscaseparameter(parameter, "REPLACEFILE")) {
|
|
|
|
|
/* replace lrzip file must be case sensitive */
|
|
|
|
|
if (iscaseparameter(parametervalue, "YES"))
|
|
|
|
|
control->flags |= FLAG_FORCE_REPLACE;
|
|
|
|
|
} else if (isparameter(parameter, "tmpdir")) {
|
|
|
|
|
control->tmpdir = realloc(NULL, strlen(parametervalue) + 2);
|
|
|
|
|
if (!control->tmpdir)
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Fatal Memory Error in read_config"), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
strcpy(control->tmpdir, parametervalue);
|
|
|
|
|
if (strcmp(parametervalue + strlen(parametervalue) - 1, "/"))
|
|
|
|
|
strcat(control->tmpdir, "/");
|
|
|
|
|
} else if (isparameter(parameter, "encrypt")) {
|
|
|
|
|
if (isparameter(parameter, "YES"))
|
|
|
|
|
control->flags |= FLAG_ENCRYPT;
|
|
|
|
|
} else
|
|
|
|
|
/* oops, we have an invalid parameter, display */
|
|
|
|
|
print_err("lrzip.conf: Unrecognized parameter value, %s = %s. Continuing.\n",\
|
|
|
|
|
parameter, parametervalue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unlikely(fclose(fp)))
|
2011-08-12 08:43:42 +02:00
|
|
|
fatal_return(("Failed to fclose fp in read_config\n"), false);
|
2011-08-11 11:44:16 +02:00
|
|
|
|
|
|
|
|
/* fprintf(stderr, "\nWindow = %d \
|
|
|
|
|
\nCompression Level = %d \
|
|
|
|
|
\nThreshold = %1.2f \
|
|
|
|
|
\nOutput Directory = %s \
|
|
|
|
|
\nFlags = %d\n", control->window,control->compression_level, control->threshold, control->outdir, control->flags);
|
|
|
|
|
*/
|
2011-08-12 08:43:42 +02:00
|
|
|
return true;
|
2011-08-11 11:44:16 +02:00
|
|
|
}
|
|
|
|
|
|
2011-03-17 04:10:58 +01:00
|
|
|
static void xor128 (void *pa, const void *pb)
|
|
|
|
|
{
|
|
|
|
|
i64 *a = pa;
|
|
|
|
|
const i64 *b = pb;
|
|
|
|
|
|
|
|
|
|
a [0] ^= b [0];
|
|
|
|
|
a [1] ^= b [1];
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-21 10:54:53 +01:00
|
|
|
static void lrz_keygen(const rzip_control *control, const uchar *salt, uchar *key, uchar *iv)
|
|
|
|
|
{
|
|
|
|
|
uchar buf [HASH_LEN + SALT_LEN + PASS_LEN];
|
|
|
|
|
mlock(buf, HASH_LEN + SALT_LEN + PASS_LEN);
|
|
|
|
|
|
|
|
|
|
memcpy(buf, control->hash, HASH_LEN);
|
|
|
|
|
memcpy(buf + HASH_LEN, salt, SALT_LEN);
|
|
|
|
|
memcpy(buf + HASH_LEN + SALT_LEN, control->salt_pass, control->salt_pass_len);
|
|
|
|
|
sha4(buf, HASH_LEN + SALT_LEN + control->salt_pass_len, key, 0);
|
|
|
|
|
|
|
|
|
|
memcpy(buf, key, HASH_LEN);
|
|
|
|
|
memcpy(buf + HASH_LEN, salt, SALT_LEN);
|
|
|
|
|
memcpy(buf + HASH_LEN + SALT_LEN, control->salt_pass, control->salt_pass_len);
|
|
|
|
|
sha4(buf, HASH_LEN + SALT_LEN + control->salt_pass_len, iv, 0);
|
|
|
|
|
|
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
|
munlock(buf, sizeof(buf));
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
bool lrz_crypt(const rzip_control *control, uchar *buf, i64 len, const uchar *salt, int encrypt)
|
2011-03-17 04:10:58 +01:00
|
|
|
{
|
|
|
|
|
/* Encryption requires CBC_LEN blocks so we can use ciphertext
|
|
|
|
|
* stealing to not have to pad the block */
|
2011-03-21 10:54:53 +01:00
|
|
|
uchar key[HASH_LEN], iv[HASH_LEN];
|
2011-03-18 00:22:58 +01:00
|
|
|
uchar tmp0[CBC_LEN], tmp1[CBC_LEN];
|
|
|
|
|
aes_context aes_ctx;
|
2011-03-17 04:10:58 +01:00
|
|
|
i64 N, M;
|
2011-08-12 08:43:42 +02:00
|
|
|
bool ret = false;
|
2011-03-17 14:06:11 +01:00
|
|
|
|
|
|
|
|
/* Generate unique key and IV for each block of data based on salt */
|
2011-03-18 00:22:58 +01:00
|
|
|
mlock(&aes_ctx, sizeof(aes_ctx));
|
2011-03-21 10:54:53 +01:00
|
|
|
mlock(key, HASH_LEN);
|
|
|
|
|
mlock(iv, HASH_LEN);
|
|
|
|
|
|
|
|
|
|
lrz_keygen(control, salt, key, iv);
|
2011-03-17 04:10:58 +01:00
|
|
|
|
|
|
|
|
M = len % CBC_LEN;
|
|
|
|
|
N = len - M;
|
|
|
|
|
|
2011-03-19 04:04:22 +01:00
|
|
|
if (encrypt == LRZ_ENCRYPT) {
|
2011-03-17 04:10:58 +01:00
|
|
|
print_maxverbose("Encrypting data \n");
|
2011-03-18 00:22:58 +01:00
|
|
|
if (unlikely(aes_setkey_enc(&aes_ctx, key, 128)))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_goto(("Failed to aes_setkey_enc in lrz_crypt\n"), error);
|
2011-03-18 00:22:58 +01:00
|
|
|
aes_crypt_cbc(&aes_ctx, AES_ENCRYPT, N, iv, buf, buf);
|
2011-08-13 10:06:30 +02:00
|
|
|
|
2011-03-17 04:10:58 +01:00
|
|
|
if (M) {
|
2011-03-18 00:22:58 +01:00
|
|
|
memset(tmp0, 0, CBC_LEN);
|
2011-03-17 04:10:58 +01:00
|
|
|
memcpy(tmp0, buf + N, M);
|
2011-03-18 00:22:58 +01:00
|
|
|
aes_crypt_cbc(&aes_ctx, AES_ENCRYPT, CBC_LEN,
|
|
|
|
|
iv, tmp0, tmp1);
|
2011-03-17 04:10:58 +01:00
|
|
|
memcpy(buf + N, buf + N - CBC_LEN, M);
|
|
|
|
|
memcpy(buf + N - CBC_LEN, tmp1, CBC_LEN);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2011-03-18 00:22:58 +01:00
|
|
|
if (unlikely(aes_setkey_dec(&aes_ctx, key, 128)))
|
2011-08-12 08:43:42 +02:00
|
|
|
failure_goto(("Failed to aes_setkey_dec in lrz_crypt\n"), error);
|
2011-03-17 04:10:58 +01:00
|
|
|
print_maxverbose("Decrypting data \n");
|
|
|
|
|
if (M) {
|
2011-03-18 00:22:58 +01:00
|
|
|
aes_crypt_cbc(&aes_ctx, AES_DECRYPT, N - CBC_LEN,
|
|
|
|
|
iv, buf, buf);
|
|
|
|
|
aes_crypt_ecb(&aes_ctx, AES_DECRYPT,
|
2011-03-17 04:10:58 +01:00
|
|
|
buf + N - CBC_LEN, tmp0);
|
|
|
|
|
memset(tmp1, 0, CBC_LEN);
|
|
|
|
|
memcpy(tmp1, buf + N, M);
|
|
|
|
|
xor128(tmp0, tmp1);
|
|
|
|
|
memcpy(buf + N, tmp0, M);
|
|
|
|
|
memcpy(tmp1 + M, tmp0 + M, CBC_LEN - M);
|
2011-03-18 00:22:58 +01:00
|
|
|
aes_crypt_ecb(&aes_ctx, AES_DECRYPT, tmp1,
|
2011-03-17 04:10:58 +01:00
|
|
|
buf + N - CBC_LEN);
|
2011-03-18 00:22:58 +01:00
|
|
|
xor128(buf + N - CBC_LEN, iv);
|
2011-03-17 04:10:58 +01:00
|
|
|
} else
|
2011-03-18 00:22:58 +01:00
|
|
|
aes_crypt_cbc(&aes_ctx, AES_DECRYPT, len,
|
|
|
|
|
iv, buf, buf);
|
2011-03-17 04:10:58 +01:00
|
|
|
}
|
2011-03-17 14:06:11 +01:00
|
|
|
|
2011-08-12 08:43:42 +02:00
|
|
|
ret = true;
|
|
|
|
|
error:
|
2011-03-18 00:22:58 +01:00
|
|
|
memset(&aes_ctx, 0, sizeof(aes_ctx));
|
2011-03-21 10:54:53 +01:00
|
|
|
memset(iv, 0, HASH_LEN);
|
|
|
|
|
memset(key, 0, HASH_LEN);
|
2011-03-18 00:22:58 +01:00
|
|
|
munlock(&aes_ctx, sizeof(aes_ctx));
|
2011-03-21 10:54:53 +01:00
|
|
|
munlock(iv, HASH_LEN);
|
|
|
|
|
munlock(key, HASH_LEN);
|
2011-08-12 08:43:42 +02:00
|
|
|
return ret;
|
2011-03-18 00:22:58 +01:00
|
|
|
}
|
|
|
|
|
|
2011-03-21 10:54:53 +01:00
|
|
|
void lrz_stretch(rzip_control *control)
|
2011-03-19 04:04:22 +01:00
|
|
|
{
|
2011-03-21 10:54:53 +01:00
|
|
|
sha4_context ctx;
|
|
|
|
|
i64 j, n, counter;
|
|
|
|
|
|
|
|
|
|
mlock(&ctx, sizeof(ctx));
|
|
|
|
|
sha4_starts(&ctx, 0);
|
|
|
|
|
|
|
|
|
|
n = control->encloops * HASH_LEN / (control->salt_pass_len + sizeof(i64));
|
|
|
|
|
print_maxverbose("Hashing passphrase %lld (%lld) times \n", control->encloops, n);
|
|
|
|
|
for (j = 0; j < n; j ++) {
|
|
|
|
|
counter = htole64(j);
|
|
|
|
|
sha4_update(&ctx, (uchar *)&counter, sizeof(counter));
|
|
|
|
|
sha4_update(&ctx, control->salt_pass, control->salt_pass_len);
|
2011-03-18 00:22:58 +01:00
|
|
|
}
|
2011-03-21 10:54:53 +01:00
|
|
|
sha4_finish(&ctx, control->hash);
|
|
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
|
munlock(&ctx, sizeof(ctx));
|
2011-03-18 00:22:58 +01:00
|
|
|
}
|