summaryrefslogtreecommitdiffstats
path: root/lib/crypt_plain.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypt_plain.c')
-rw-r--r--lib/crypt_plain.c117
1 files changed, 117 insertions, 0 deletions
diff --git a/lib/crypt_plain.c b/lib/crypt_plain.c
new file mode 100644
index 0000000..c839b09
--- /dev/null
+++ b/lib/crypt_plain.c
@@ -0,0 +1,117 @@
+/*
+ * cryptsetup plain device helper functions
+ *
+ * Copyright (C) 2004 Jana Saout <jana@saout.de>
+ * Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010-2023 Milan Broz
+ *
+ * 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.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "libcryptsetup.h"
+#include "internal.h"
+
+static int hash(const char *hash_name, size_t key_size, char *key,
+ size_t passphrase_size, const char *passphrase)
+{
+ struct crypt_hash *md = NULL;
+ size_t len;
+ int round, i, r = 0;
+
+ if (crypt_hash_init(&md, hash_name))
+ return -ENOENT;
+
+ len = crypt_hash_size(hash_name);
+
+ for(round = 0; key_size && !r; round++) {
+ /* hack from hashalot to avoid null bytes in key */
+ for(i = 0; i < round; i++)
+ if (crypt_hash_write(md, "A", 1))
+ r = 1;
+
+ if (crypt_hash_write(md, passphrase, passphrase_size))
+ r = 1;
+
+ if (len > key_size)
+ len = key_size;
+
+ if (crypt_hash_final(md, key, len))
+ r = 1;
+
+ key += len;
+ key_size -= len;
+ }
+
+ crypt_hash_destroy(md);
+ return r;
+}
+
+#define PLAIN_HASH_LEN_MAX 256
+
+int crypt_plain_hash(struct crypt_device *cd,
+ const char *hash_name,
+ char *key, size_t key_size,
+ const char *passphrase, size_t passphrase_size)
+{
+ char hash_name_buf[PLAIN_HASH_LEN_MAX], *s;
+ size_t hash_size, pad_size;
+ int r;
+
+ log_dbg(cd, "Plain: hashing passphrase using %s.", hash_name);
+
+ if (strlen(hash_name) >= PLAIN_HASH_LEN_MAX)
+ return -EINVAL;
+ strncpy(hash_name_buf, hash_name, PLAIN_HASH_LEN_MAX);
+ hash_name_buf[PLAIN_HASH_LEN_MAX - 1] = '\0';
+
+ /* hash[:hash_length] */
+ if ((s = strchr(hash_name_buf, ':'))) {
+ *s = '\0';
+ s++;
+ if (!*s || sscanf(s, "%zd", &hash_size) != 1) {
+ log_dbg(cd, "Hash length is not a number");
+ return -EINVAL;
+ }
+ if (hash_size > key_size) {
+ log_dbg(cd, "Hash length %zd > key length %zd",
+ hash_size, key_size);
+ return -EINVAL;
+ }
+ pad_size = key_size - hash_size;
+ } else {
+ hash_size = key_size;
+ pad_size = 0;
+ }
+
+ /* No hash, copy passphrase directly */
+ if (!strcmp(hash_name_buf, "plain")) {
+ if (passphrase_size < hash_size) {
+ log_dbg(cd, "Too short plain passphrase.");
+ return -EINVAL;
+ }
+ memcpy(key, passphrase, hash_size);
+ r = 0;
+ } else
+ r = hash(hash_name_buf, hash_size, key, passphrase_size, passphrase);
+
+ if (r == 0 && pad_size)
+ memset(key + hash_size, 0, pad_size);
+
+ return r;
+}