/*
* cryptsetup plain device helper functions
*
- * Copyright (C) 2004 Christophe Saout <christophe@saout.de>
- * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004 Jana Saout <jana@saout.de>
+ * Copyright (C) 2010-2021 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
+ * 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
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
-#include <stdlib.h>
+#include <stdio.h>
#include <errno.h>
+#include "libcryptsetup.h"
#include "internal.h"
-#include "crypto_backend.h"
-static int hash(const char *hash_name, int size, char *key,
- int sizep, const char *passphrase)
+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 slen;
- int len = crypt_hash_size(hash_name);
- int round, i;
+ size_t len;
+ int round, i, r = 0;
if (crypt_hash_init(&md, hash_name))
return -ENOENT;
- for(round = 0; size; round++) {
+ 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++)
- crypt_hash_write(md, "A", 1);
+ if (crypt_hash_write(md, "A", 1))
+ r = 1;
+
+ if (crypt_hash_write(md, passphrase, passphrase_size))
+ r = 1;
- crypt_hash_write(md, passphrase, sizep);
+ if (len > key_size)
+ len = key_size;
- if (len > size)
- len = size;
- slen = len;
- crypt_hash_final(md, key, slen);
- // FIXME: if slen != len
+ if (crypt_hash_final(md, key, len))
+ r = 1;
key += len;
- size -= len;
- if (size)
- crypt_hash_restart(md);
+ key_size -= len;
}
crypt_hash_destroy(md);
- return 0;
+ return r;
}
-int crypt_plain_hash(struct crypt_device *ctx, const char *hash_name,
- char *result, size_t size,
- const char *passphrase, size_t sizep)
+#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[256], *s;
- size_t hlen, pad = 0;
+ char hash_name_buf[PLAIN_HASH_LEN_MAX], *s;
+ size_t hash_size, pad_size;
int r;
- if (strlen(hash_name) >= sizeof(hash_name_buf))
+ 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';
- if ((s = strchr(hash_name, ':'))) {
- strcpy(hash_name_buf, hash_name);
- hash_name_buf[s-hash_name] = '\0';
- hash_name = hash_name_buf;
- hlen = atoi(++s);
- if (hlen > size) {
- log_err(ctx, "Requested hash length (%zd) > key length (%zd)\n", hlen, size);
+ /* 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;
}
- pad = size-hlen;
- size = hlen;
+ 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;
}
- r = hash(hash_name, size, result, sizep, passphrase);
- if (r < 0)
- log_err(ctx, "Hash algorithm %s not supported.\n", hash_name);
+ /* 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)
- memset(result+size, 0, pad);
+ if (r == 0 && pad_size)
+ memset(key + hash_size, 0, pad_size);
return r;
}