aboutsummaryrefslogtreecommitdiffstats
path: root/src/file2key.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/file2key.c')
-rw-r--r--src/file2key.c324
1 files changed, 210 insertions, 114 deletions
diff --git a/src/file2key.c b/src/file2key.c
index 99347d7..4288ffc 100644
--- a/src/file2key.c
+++ b/src/file2key.c
@@ -16,171 +16,267 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "keccak.h"
-
#include <stdio.h>
-#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <stddef.h>
#include <string.h>
#include <stdlib.h>
+#include <fcntl.h>
#include <passphrase.h>
+#include <libkeccak.h>
+
/**
* Random string created with `dd if=/dev/random bs=1024 count=1 | tr -d -c a-zA-Z0-9`
- *
- * DO NOT EDIT!
*/
#define STATIC_SALT "5EbppWrYxMuBKQmbDz8rOCVCONsSLas74qrjMLTiJqsYWcTePNeshVXcmAWGkh88VeFh"
+/**
+ * Prompt string that tells you to enter your passphrase
+ */
+#ifndef PASSPHRASE_PROMPT_STRING
+# define PASSPHRASE_PROMPT_STRING "[file2key] Enter passphrase: "
+# warning: you should personalise PASSPHRASE_PROMPT_STRING.
+#endif
+
+/**
+ * The rate parameter for the Keccak sponge when hashing master passphrase
+ */
+#ifndef PASSPHRASE_KECCAK_RATE
+# define PASSPHRASE_KECCAK_RATE 576
+#endif
+
+/**
+ * The capacity parameter for the Keccak sponge when hashing master passphrase
+ */
+#ifndef PASSPHRASE_KECCAK_CAPACITY
+# define PASSPHRASE_KECCAK_CAPACITY 1024
+#endif
+
+/**
+ * The output parameter for the Keccak sponge when hashing master passphrase
+ */
+#ifndef PASSPHRASE_KECCAK_OUTPUT
+# define PASSPHRASE_KECCAK_OUTPUT 32
+#endif
+
+/**
+ * The number of times to squeeze the master passphrase
+ */
+#ifndef PASSPHRASE_KECCAK_SQUEEZES
+# define PASSPHRASE_KECCAK_SQUEEZES 10000
+#endif
+
+
+/**
+ * Map from hexadecimal to colour-coded hexadecimal
+ */
const char* const COLOUR_HEX[] =
{
- "\033[31m0",
- "\033[31m1",
- "\033[31m2",
- "\033[31m3",
- "\033[31m4",
- "\033[32m5",
- "\033[32m6",
- "\033[32m7",
- "\033[32m8",
- "\033[32m9",
- "\033[34ma",
- "\033[34mb",
- "\033[34mc",
- "\033[34md",
- "\033[34me",
- "\033[34mf",
+ ['0'] = "\033[31m0",
+ ['1'] = "\033[31m1",
+ ['2'] = "\033[31m2",
+ ['3'] = "\033[31m3",
+ ['4'] = "\033[31m4",
+ ['5'] = "\033[32m5",
+ ['6'] = "\033[32m6",
+ ['7'] = "\033[32m7",
+ ['8'] = "\033[32m8",
+ ['9'] = "\033[32m9",
+ ['a'] = "\033[34ma",
+ ['b'] = "\033[34mb",
+ ['c'] = "\033[34mc",
+ ['d'] = "\033[34md",
+ ['e'] = "\033[34me",
+ ['f'] = "\033[34mf",
};
-int main(int argc, char** argv)
+#define USER_ERROR(string) \
+ (fprintf(stderr, "%s: %s.\n", execname, string), 1)
+
+#define tt(expr) if ((r = (expr))) goto fail
+
+#define t(expr) if (expr) goto pfail
+
+
+
+/**
+ * `argv[0]` from `main`
+ */
+static char* execname;
+
+
+
+/**
+ * Ask the user for the passphrase
+ *
+ * @param passphrase Output parameter for the passphrase
+ * @return Zero on success, an appropriate exit value on error
+ */
+static int get_passphrase(char** passphrase)
{
- int is_echo_disabled = 0;
- int is_hash_initialised = 0;
+ passphrase_disable_echo();
+ fprintf(stderr, "%s", PASSPHRASE_PROMPT_STRING);
+ fflush(stderr);
+ *passphrase = passphrase_read();
+ if (*passphrase == NULL)
+ perror(execname);
+ passphrase_reenable_echo();
+ return *passphrase ? 0 : 2;
+}
+
+
+/**
+ * Hash, and display, passphrase so to hint the
+ * user whether it as typed correctly or not
+ *
+ * @param passphrase The passphrase
+ * @return Zero on success, an appropriate exit value on error
+ */
+static int hash_passphrase(const char* passphrase)
+{
+#define SQUEEZES PASSPHRASE_KECCAK_SQUEEZES
+ libkeccak_spec_t spec;
+ libkeccak_state_t state;
+ char hashsum[PASSPHRASE_KECCAK_OUTPUT / 8];
+ char hexsum[PASSPHRASE_KECCAK_OUTPUT / 4 + 1];
+ size_t i, n;
+
+ spec.bitrate = PASSPHRASE_KECCAK_RATE;
+ spec.capacity = PASSPHRASE_KECCAK_CAPACITY;
+ spec.output = PASSPHRASE_KECCAK_OUTPUT;
+
+ if (libkeccak_spec_check(&spec) || (SQUEEZES <= 0))
+ return USER_ERROR("bad passhprase hashing parameters, please recompile file2key with with "
+ "proper values on PASSPHRASE_KECCAK_RATE, PASSPHRASE_KECCAK_CAPACITY, "
+ "PASSPHRASE_KECCAK_OUTPUT and PASSPHRASE_KECCAK_SQUEEZES");
+
+ if (libkeccak_state_initialise(&state, &spec))
+ return perror(execname), 2;
+
+ if (libkeccak_digest(&state, passphrase, strlen(passphrase), 0, NULL, SQUEEZES == 1 ? hashsum : NULL))
+ return perror(execname), libkeccak_state_destroy(&state), 2;
+ if (SQUEEZES > 2) libkeccak_fast_squeeze(&state, SQUEEZES - 2);
+ if (SQUEEZES > 1) libkeccak_squeeze(&state, hashsum);
+
+ libkeccak_state_destroy(&state);
- FILE* file = NULL;
+ libkeccak_behex_lower(hexsum, hashsum, sizeof(hashsum) / sizeof(char));
+ fprintf(stderr, "%s: passphrase hash: ", execname);
+ for (i = 0, n = strlen(hexsum); i < n; i++)
+ fprintf(stderr, "%s", COLOUR_HEX[(unsigned char)(hexsum[i])]);
+ fprintf(stderr, "\033[00m\n");
+
+ return 0;
+#undef SQUEEZES
+}
+
+
+/**
+ * Here we go!
+ *
+ * @param argc The number of command line argumnets
+ * @param argv Command line argumnets
+ * @return Zero on success, 1 on user error, 2 on system error
+ */
+int main(int argc, char** argv)
+{
+ libkeccak_generalised_spec_t gspec;
+ libkeccak_spec_t spec;
+ libkeccak_state_t state;
char* passphrase = NULL;
- size_t passphrase_n;
- char* hash;
+ char* hash = NULL;
+ size_t hash_size = 0;
+ size_t hash_ptr = 0;
char* data = NULL;
- size_t ptr;
- size_t blksize;
- size_t got;
+ size_t data_size = 0;
+ size_t data_ptr = 0;
+ size_t blksize = 4096;
+ int r, fd = -1;
struct stat attr;
- if ((argc != 2) || (argv[1][0] == '-'))
- {
- printf("USAGE: %s FILE\n", *argv);
- return 0;
- }
+ execname = *argv;
- if (stat(argv[1], &attr) < 0)
- goto pfail;
- if (S_ISREG(attr.st_mode) == 0)
+ if ((argc != 2) || (argv[1][0] == '-'))
{
- fprintf(stderr, "%s: input file is not a regular file\n", *argv);
- goto fail;
+ fprintf(stderr, "USAGE: %s FILE\n", execname);
+ return !!strcmp(argv[1], "--help");
}
- if (attr.st_size < 100 << 10)
- fprintf(stderr, "%s: warning: input file is small (less than 100 KB)\n", *argv);
- file = fopen(argv[1], "r");
- if (file == NULL)
- goto pfail;
- data = malloc((size_t)(attr.st_size) * sizeof(char));
- if (data == NULL)
- goto pfail;
+ libkeccak_generalised_spec_initialise(&gspec);
+ libkeccak_degeneralise_spec(&gspec, &spec);
+ t (libkeccak_state_initialise(&state, &spec));
- blksize = attr.st_blksize ? (size_t)(attr.st_blksize) : (size_t)(8 << 10);
+ tt (get_passphrase(&passphrase));
+ tt (hash_passphrase(passphrase));
- for (ptr = 0; ptr < (size_t)(attr.st_size); ptr += got)
- {
- got = fread(data + ptr, 1, blksize, file);
- if (got < blksize)
- {
- if (ferror(file))
- goto pfail;
- break;
- }
- }
+ t (libkeccak_update(&state, passphrase, strlen(passphrase)));
- fclose(file), file = NULL;
+ passphrase_wipe(passphrase, strlen(passphrase));
+ free(passphrase), passphrase = NULL;
- passphrase_disable_echo(), is_echo_disabled = 1;
- fprintf(stderr, "[%s] Enter passphrase: ", *argv);
- fflush(stderr);
- passphrase = passphrase_read();
- if (passphrase == NULL)
- goto pfail;
- passphrase_n = strlen(passphrase);
- passphrase_reenable_echo(), is_echo_disabled = 0;
+ t ((fd = open(argv[1], O_RDONLY), fd < 0));
+ if (fstat(fd, &attr) == 0)
+ if (attr.st_blksize > 0)
+ blksize = (size_t)(attr.st_blksize);
- initialise(), is_hash_initialised = 1;
+ hash_size = (size_t)(spec.output / 8);
+ t ((hash = malloc(hash_size), hash == NULL));
+ t ((data = malloc(blksize), data == NULL));
- update(passphrase, passphrase_n);
- passphrase_wipe(passphrase, passphrase_n);
- free(passphrase), passphrase = NULL;
+ t (libkeccak_digest(&state, STATIC_SALT, strlen(STATIC_SALT), 0, NULL, hash));
- for (ptr = 0; ptr < (size_t)(attr.st_size); ptr += 72)
+ for (;;)
{
- size_t i, n = (size_t)(attr.st_size) - ptr;
- if (n > 72)
- n = 72;
+ size_t start;
+ ssize_t n;
- if (ptr == 0)
+ if (hash_ptr == hash_size)
+ libkeccak_squeeze(&state, hash), hash_ptr = 0;
+
+ if (data_ptr == data_size)
{
- char* phash = malloc((20 * 6) + 1 * sizeof(char));
- if (phash == NULL)
- goto pfail;
- hash = digest(STATIC_SALT, strlen(STATIC_SALT));
-
- for (i = 0; i < 10; i++)
- {
- memcpy(phash + (i * 2 + 0) * 6, COLOUR_HEX[((unsigned char)(hash[i]) >> 4) & 15], 6 * sizeof(char));
- memcpy(phash + (i * 2 + 1) * 6, COLOUR_HEX[((unsigned char)(hash[i]) >> 0) & 15], 6 * sizeof(char));
- }
- phash[20 * 6] = '\0';
-
- fprintf(stderr, "%s: passphrase hash: %s\033[00m\n", *argv, phash);
- free(phash);
+ n = read(fd, data, blksize);
+ t (n < 0);
+ if (n == 0)
+ break;
+ data_size = (size_t)n;
}
- else
- hash = squeeze();
- for (i = 0; i < n; i++)
- *(hash + i) ^= *(data + ptr + i);
+ start = data_ptr;
+ while ((hash_ptr < hash_size) && (data_ptr < data_size))
+ data[data_ptr++] ^= hash[hash_ptr++];
- if (fwrite(hash, 1, n, stdout) < n)
- goto pfail;
+ while (start < data_ptr)
+ {
+ n = write(STDOUT_FILENO, data + start, data_ptr - start);
+ t (n <= 0);
+ start += (size_t)n;
+ }
}
- free(data), data = NULL;
- dispose(), is_hash_initialised = 0;
- return 0;
+ r = 0;
+ goto done;
pfail:
+ r = 2;
perror(*argv);
fail:
- if (file)
- fclose(file);
- if (data)
- free(data);
- if (is_echo_disabled)
- passphrase_reenable_echo();
if (passphrase)
- {
- passphrase_wipe(passphrase, passphrase_n);
- free(passphrase);
- }
- if (is_hash_initialised)
- dispose();
- return 1;
+ passphrase_wipe(passphrase, strlen(passphrase));
+ free(passphrase);
+ done:
+ libkeccak_state_destroy(&state);
+ free(data);
+ free(hash);
+ if (fd >= 0)
+ close(fd);
+ return r;
}