File mokutil-support-crypt-hash-methods.patch of Package mokutil

From c5d08b63d47db48bd239599f8fb53b13f879e1ff Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Wed, 23 Jan 2013 18:31:19 +0800
Subject: [PATCH 1/9] Use crypt_r() to generate the password hash

1. We now use crypt_r() from glibc to generate the password hash.

2. The password length is changed to be compatible with the password
   hash from /etc/shadow.

3. The password hash structure was modified to be compatible with
   the change in MokManager.
---
 configure.ac         |    2 +-
 src/Makefile.am      |    3 +
 src/PasswordHash.h   |   33 --------
 src/mokutil.c        |  219 ++++++++++++++++++++++----------------------------
 src/password-crypt.c |  218 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/password-crypt.h |   42 ++++++++++
 6 files changed, 359 insertions(+), 158 deletions(-)
 delete mode 100644 src/PasswordHash.h
 create mode 100644 src/password-crypt.c
 create mode 100644 src/password-crypt.h

diff --git a/configure.ac b/configure.ac
index 468b108..894790e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,7 +15,7 @@ AM_PROG_CC_C_O
 AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [turn on debug]), CFLAGS="$CFLAGS -g")
 
 # Checks for header files.
-AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h])
+AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h crypt.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_INLINE
diff --git a/src/Makefile.am b/src/Makefile.am
index 036a62a..afe1752 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,7 @@
 bin_PROGRAMS    = mokutil
 
 mokutil_CFLAGS  = $(OPENSSL_CFLAGS) \
+		  -lcrypt \
 		  $(WARNINGFLAGS_C)
 
 mokutil_LDADD   = $(OPENSSL_LIBS)
@@ -8,4 +9,6 @@ mokutil_LDADD   = $(OPENSSL_LIBS)
 mokutil_SOURCES = efi.h \
 		  efilib.c \
 		  signature.h \
+		  password-crypt.h \
+		  password-crypt.c \
 		  mokutil.c
diff --git a/src/PasswordHash.h b/src/PasswordHash.h
deleted file mode 100644
index 2aeded6..0000000
--- a/src/PasswordHash.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __PASSWORD_HASH_H__
-#define __PASSWORD_HASH_H__
-
-#include <sys/types.h>
-
-#define PASSWORD_HASH_SIZE 88
-
-/* The max salt size (in bits) */
-#define T_DES_SALT_MAX 12
-#define E_BSI_DES_SALT_MAX 24
-#define MD5_SALT_MAX 48
-#define SHA256_SALT_MAX 96
-#define SHA512_SALT_MAX 96
-#define BLOWFISH_SALT_MAX 128
-
-enum HashMethod {
-	Tranditional_DES = 0,
-	Extend_BSDI_DES,
-	MD5_BASED,
-	SHA256_BASED,
-	SHA512_BASED,
-	BLOWFISH_BASED
-};
-
-typedef struct {
-	uint16_t method;
-	uint32_t iter_count;
-	uint16_t salt_size;
-	uint8_t  salt[16];
-	uint8_t  hash[64];
-} __attribute__ ((packed)) pw_hash_t;
-
-#endif /* __PASSWORD_HASH_H__ */
diff --git a/src/mokutil.c b/src/mokutil.c
index 38039b9..f71cb6a 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -11,15 +11,20 @@
 #include <openssl/sha.h>
 #include <openssl/x509.h>
 
+#define __USE_GNU
+#include <crypt.h>
+
 #include "efi.h"
 #include "signature.h"
-#include "PasswordHash.h"
+#include "password-crypt.h"
 
 #define SHIM_LOCK_GUID \
 EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
 
-#define PASSWORD_MAX 16
-#define PASSWORD_MIN 8
+#define PASSWORD_MAX 256
+#define PASSWORD_MIN 1
+#define SB_PASSWORD_MAX 16
+#define SB_PASSWORD_MIN 8
 
 #define HELP               0x1
 #define LIST_ENROLLED      0x2
@@ -38,6 +43,9 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b,
 #define HASH_FILE          0x4000
 #define GENERATE_PW_HASH   0x8000
 
+#define DEFAULT_CRYPT_METHOD SHA256_BASED
+#define DEFAULT_SALT_SIZE    SHA256_SALT_MAX
+
 typedef struct {
 	uint32_t mok_size;
 	void    *mok;
@@ -46,7 +54,7 @@ typedef struct {
 typedef struct {
 	uint32_t mok_sb_state;
 	uint32_t password_length;
-	uint16_t password[PASSWORD_MAX];
+	uint16_t password[SB_PASSWORD_MAX];
 } MokSBVar;
 
 static void
@@ -71,8 +79,6 @@ print_help ()
 	printf ("  --test-key <der file>\t\t\tTest if the key is enrolled or not\n");
 	printf ("  --reset\t\t\t\tReset MOK list\n");
 	printf ("  --generate-hash[=password]\t\tGenerate the password hash\n");
-	printf ("\n");
-	printf ("Suboptions:\n");
 	printf ("  --hash-file <hash file>\t\tUse the specific password hash\n");
 	printf ("                         \t\t(Only valid with --import, --delete,\n");
 	printf ("                         \t\t --password, and --reset)\n");
@@ -310,7 +316,7 @@ get_password (char **password, int *len, int min, int max)
 	fail = 0;
 
 	while (fail < 3) {
-		printf ("input password (%d~%d characters): ", min, max);
+		printf ("input password: ");
 		len_1 = read_hidden_line (&password_1, &n);
 		printf ("\n");
 
@@ -361,103 +367,79 @@ error:
 static unsigned int
 generate_salt (uint8_t salt[], unsigned int max_size, unsigned int min_size)
 {
-	unsigned int salt_len = max_size / 8;
+	unsigned int salt_size = max_size;
 	int i;
 
+	/* TODO use a better random number generator */
 	srand (time (NULL));
 
-	for (i = 0; i < salt_len; i++)
-		salt[i] = rand() % 256;
+	for (i = 0; i < salt_size; i++)
+		salt[i] = int_to_b64 (rand() % 0x3f);
 
-	return max_size;
+	return salt_size;
 }
 
 static int
-generate_hash (void *salt, unsigned int salt_len, char *password,
-	       int pw_len, uint8_t *auth)
+generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len)
 {
-	SHA256_CTX ctx;
-
-	if (!password || !auth)
+	pw_crypt_t new_crypt;
+	struct crypt_data data;
+	char settings[64];
+	char *crypt_string;
+	const char *prefix;
+	int hash_len, prefix_len;
+
+	if (!password || !pw_crypt)
 		return -1;
 
-	SHA256_Init (&ctx);
-
-	if (salt)
-		SHA256_Update (&ctx, salt, salt_len);
-
-	SHA256_Update (&ctx, password, pw_len);
-
-	SHA256_Final (auth, &ctx);
-
-	return 0;
-}
-
-static int
-char_to_int (const char c)
-{
-	if (c >= '0' && c <= '9')
-		return (c - '0');
-
-	if (c >= 'A' && c <= 'F')
-		return (c - 'A' + 10);
-
-	if (c >= 'a' && c <= 'f')
-		return (c - 'a' + 10);
+	prefix = get_crypt_prefix (pw_crypt->method);
+	if (!prefix)
+		return -1;
+	prefix_len = strlen(prefix);
 
-	return -1;
-}
+	strncpy (settings, prefix, prefix_len);
+	strncpy (settings + prefix_len, (const char *)pw_crypt->salt,
+		 pw_crypt->salt_size);
+	settings[pw_crypt->salt_size + prefix_len] = '\0';
 
-static int
-read_hex_array (const char *string, uint8_t *out, unsigned int len)
-{
-	int i, digit_1, digit_2;
+	crypt_string = crypt_r (password, settings, &data);
+	if (!crypt_string)
+		return -1;
 
-	for (i = 0; i < len; i++) {
-		digit_1 = char_to_int (string[2*i]);
-		digit_2 = char_to_int (string[2*i + 1]);
-		if (digit_1 < 0 || digit_2 < 0)
-			return -1;
+	if (decode_pass (crypt_string, &new_crypt) < 0)
+		return -1;
 
-		out[i] = (uint8_t)digit_1 * 16 + (uint8_t)digit_2;
-	}
+	hash_len = get_hash_size (new_crypt.method);
+	if (hash_len < 0)
+		return -1;
+	memcpy (pw_crypt->hash, new_crypt.hash, hash_len);
+	pw_crypt->iter_count = new_crypt.iter_count;
 
 	return 0;
 }
 
 static int
-get_hash_from_file (const char *file, pw_hash_t *pw_hash)
+get_hash_from_file (const char *file, pw_crypt_t *pw_crypt)
 {
-	FILE *fptr;
-	unsigned int method, iter_count, salt_size;
-	char salt_string[2*(SHA256_SALT_MAX/8)];
-	char hash_string[2*SHA256_DIGEST_LENGTH];
+	char string[300];
+	ssize_t read_len;
+	int fd;
 
-	fptr = fopen (file, "r");
-	if (fptr == NULL) {
+	fd = open (file, O_RDONLY);
+	if (fd < 0) {
 		fprintf (stderr, "Failed to open %s\n", file);
 		return -1;
 	}
+	read_len = read (fd, string, 300);
+	close (fd);
 
-	memset (salt_string, 0, 2*(SHA256_SALT_MAX/8));
-	memset (hash_string, 0, 2*SHA256_DIGEST_LENGTH);
-
-	fscanf (fptr, "%x.%x.%x.%24c.%64c", &method, &iter_count, &salt_size,
-	        salt_string, hash_string);
-
-	fclose (fptr);
-
-	pw_hash->method = (uint16_t)method;
-	pw_hash->iter_count = (uint32_t)iter_count;
-	pw_hash->salt_size = (uint16_t)salt_size;
-
-	if (read_hex_array (salt_string, pw_hash->salt, salt_size/8) < 0) {
-		fprintf (stderr, "Corrupted salt\n");
+	if (string[read_len] != '\0') {
+		fprintf (stderr, "corrupted string\n");
 		return -1;
 	}
 
-	if (read_hex_array (hash_string, pw_hash->hash, SHA256_DIGEST_LENGTH) < 0) {
-		fprintf (stderr, "Corrupted hash\n");
+	if (decode_pass (string, pw_crypt) < 0) {
+		fprintf (stderr, "Failed to parse the string\n");
 		return -1;
 	}
 
@@ -470,15 +452,13 @@ update_request (void *new_list, int list_len, uint8_t import,
 {
 	efi_variable_t var;
 	const char *req_name, *auth_name;
-	pw_hash_t pw_hash;
+	pw_crypt_t pw_crypt;
 	char *password = NULL;
 	int pw_len;
 	int ret = -1;
 
-	bzero (&pw_hash, sizeof(pw_hash_t));
-	pw_hash.method = SHA256_BASED;
-	pw_hash.iter_count = 1;
-	pw_hash.salt_size = SHA256_SALT_MAX;
+	bzero (&pw_crypt, sizeof(pw_crypt_t));
+	pw_crypt.method = DEFAULT_CRYPT_METHOD;
 
 	if (import) {
 		req_name = "MokNew";
@@ -489,7 +469,7 @@ update_request (void *new_list, int list_len, uint8_t import,
 	}
 
 	if (hash_file) {
-		if (get_hash_from_file (hash_file, &pw_hash) < 0) {
+		if (get_hash_from_file (hash_file, &pw_crypt) < 0) {
 			fprintf (stderr, "Failed to read hash\n");
 			goto error;
 		}
@@ -499,9 +479,10 @@ update_request (void *new_list, int list_len, uint8_t import,
 			goto error;
 		}
 
-		generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0);
-		if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password,
-				   pw_len, pw_hash.hash) < 0) {
+		pw_crypt.salt_size = generate_salt (pw_crypt.salt,
+						    DEFAULT_SALT_SIZE,
+						    DEFAULT_SALT_SIZE);
+		if (generate_hash (&pw_crypt, password, pw_len) < 0) {
 			fprintf (stderr, "Couldn't generate hash\n");
 			goto error;
 		}
@@ -528,8 +509,8 @@ update_request (void *new_list, int list_len, uint8_t import,
 	}
 
 	/* Write MokAuth or MokDelAuth */
-	var.Data = (void *)&pw_hash;
-	var.DataSize = PASSWORD_HASH_SIZE;
+	var.Data = (void *)&pw_crypt;
+	var.DataSize = PASSWORD_CRYPT_SIZE;
 	var.VariableName = auth_name;
 
 	var.VendorGuid = SHIM_LOCK_GUID;
@@ -853,18 +834,16 @@ static int
 set_password (const char *hash_file)
 {
 	efi_variable_t var;
-	pw_hash_t pw_hash;
+	pw_crypt_t pw_crypt;
 	char *password = NULL;
 	int pw_len;
 	int ret = -1;
 
-	bzero (&pw_hash, sizeof(pw_hash_t));
-	pw_hash.method = SHA256_BASED;
-	pw_hash.iter_count = 1;
-	pw_hash.salt_size = SHA256_SALT_MAX;
+	bzero (&pw_crypt, sizeof(pw_crypt_t));
+	pw_crypt.method = DEFAULT_CRYPT_METHOD;
 
 	if (hash_file) {
-		if (get_hash_from_file (hash_file, &pw_hash) < 0) {
+		if (get_hash_from_file (hash_file, &pw_crypt) < 0) {
 			fprintf (stderr, "Failed to read hash\n");
 			goto error;
 		}
@@ -874,16 +853,17 @@ set_password (const char *hash_file)
 			goto error;
 		}
 
-		generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0);
-		if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password,
-				   pw_len, pw_hash.hash) < 0) {
+		pw_crypt.salt_size = generate_salt (pw_crypt.salt,
+						    DEFAULT_SALT_SIZE,
+						    DEFAULT_SALT_SIZE);
+		if (generate_hash (&pw_crypt, password, pw_len) < 0) {
 			fprintf (stderr, "Couldn't generate hash\n");
 			goto error;
 		}
 	}
 
-	var.Data = (void *)&pw_hash;
-	var.DataSize = PASSWORD_HASH_SIZE;
+	var.Data = (void *)&pw_crypt;
+	var.DataSize = PASSWORD_CRYPT_SIZE;
 	var.VariableName = "MokPW";
 
 	var.VendorGuid = SHIM_LOCK_GUID;
@@ -910,10 +890,11 @@ set_validation (uint32_t state)
 	MokSBVar sbvar;
 	char *password = NULL;
 	int pw_len;
-	efi_char16_t efichar_pass[PASSWORD_MAX];
+	efi_char16_t efichar_pass[SB_PASSWORD_MAX];
 	int ret = -1;
 
-        if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) {
+	printf ("password length: %d~%d\n", SB_PASSWORD_MIN, SB_PASSWORD_MAX);
+        if (get_password (&password, &pw_len, SB_PASSWORD_MIN, SB_PASSWORD_MAX) < 0) {
 		fprintf (stderr, "Abort\n");
 		goto error;
 	}
@@ -921,10 +902,10 @@ set_validation (uint32_t state)
 	sbvar.password_length = pw_len;
 
 	efichar_from_char (efichar_pass, password,
-			   PASSWORD_MAX * sizeof(efi_char16_t));
+			   SB_PASSWORD_MAX * sizeof(efi_char16_t));
 
 	memcpy(sbvar.password, efichar_pass,
-	       PASSWORD_MAX * sizeof(efi_char16_t));
+	       SB_PASSWORD_MAX * sizeof(efi_char16_t));
 
 	sbvar.mok_sb_state = state;
 
@@ -1051,20 +1032,16 @@ reset_moks (const char *hash_file)
 static int
 generate_pw_hash (const char *input_pw)
 {
-	pw_hash_t pw_hash;
+	struct crypt_data data;
+	char settings[SHA256_SALT_MAX + 3 + 1];
 	char *password = NULL;
-	int pw_len, i, ret = -1;
-
-	bzero (&pw_hash, sizeof(pw_hash_t));
-	pw_hash.method = SHA256_BASED;
-	pw_hash.iter_count = 1;
-	pw_hash.salt_size = SHA256_SALT_MAX;
+	char *crypt_string;
+	int pw_len, ret = -1;
 
 	if (input_pw) {
 		pw_len = strlen (input_pw);
 		if (pw_len > PASSWORD_MAX || pw_len < PASSWORD_MIN) {
-			fprintf (stderr, "password should be %d~%d characters\n",
-				 PASSWORD_MIN, PASSWORD_MAX);
+			fprintf (stderr, "invalid password length\n");
 			return -1;
 		}
 
@@ -1081,23 +1058,17 @@ generate_pw_hash (const char *input_pw)
 		}
 	}
 
-	generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0);
-	if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password,
-			   pw_len, pw_hash.hash) < 0) {
-		fprintf (stderr, "Couldn't generate hash\n");
+	strncpy (settings, "$5$", 3);
+	generate_salt ((uint8_t *)(settings + 3), SHA256_SALT_MAX, 0);
+	settings[SHA256_SALT_MAX + 3] = '\0';
+
+	crypt_string = crypt_r (password, settings, &data);
+	if (!crypt_string) {
+		fprintf (stderr, "Failed to generate hash\n");
 		goto error;
 	}
 
-	/* Print the salt and hash */
-	printf ("%x.%x.%x.", pw_hash.method, pw_hash.iter_count,
-	       pw_hash.salt_size);
-	for (i = 0; i < (SHA256_SALT_MAX/8); i++) {
-		printf ("%x%x", pw_hash.salt[i]/16, pw_hash.salt[i]%16);
-	}
-	putchar ('.');
-	for (i = 0; i < SHA256_DIGEST_LENGTH; i++)
-		printf ("%x%x", pw_hash.hash[i]/16, pw_hash.hash[i]%16);
-	putchar ('\n');
+	printf ("%s\n", crypt_string);
 
 	ret = 0;
 error:
diff --git a/src/password-crypt.c b/src/password-crypt.c
new file mode 100644
index 0000000..f004049
--- /dev/null
+++ b/src/password-crypt.c
@@ -0,0 +1,218 @@
+#include <string.h>
+#include <stdlib.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include "password-crypt.h"
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#define SHA256_DEFAULT_ROUNDS 5000
+
+static const char b64t[64] =
+"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static const char sha256_prefix[] = "$5$";
+static const char sha512_prefix[] = "$6$";
+
+static const char sha256_rounds_prefix[] = "rounds=";
+
+static int restore_sha256_array (const char *string, uint8_t *hash);
+
+int
+get_hash_size (int method)
+{
+	switch (method) {
+	case TRANDITIONAL_DES:
+		return 64 / 8; /* per "man crypt" */
+	case EXTEND_BSDI_DES:
+		return 64 / 8; /* per "man crypt" */
+	case MD5_BASED:
+		return MD5_DIGEST_LENGTH;
+	case SHA256_BASED:
+		return SHA256_DIGEST_LENGTH;
+	case SHA512_BASED:
+		return SHA512_DIGEST_LENGTH;
+	case BLOWFISH_BASED:
+		return 184 / 8; /* per "man crypt" */
+	}
+
+	return -1;
+}
+
+const char *
+get_crypt_prefix (int method)
+{
+	switch (method) {
+	case TRANDITIONAL_DES:
+		return ""; /* per "man crypt" */
+	case EXTEND_BSDI_DES:
+		return "_"; /* per "man crypt" */
+	case MD5_BASED:
+		return "$1$";
+	case SHA256_BASED:
+		return "$5$";
+	case SHA512_BASED:
+		return "$6$";
+	case BLOWFISH_BASED:
+		return "$2y$"; /* per "man crypt" */
+	}
+
+	return NULL;
+}
+
+static int
+decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt)
+{
+	/* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{43} */
+	char *tmp, *ptr = (char *)string;
+	char *b64_hash;
+	int count = 0;
+
+	/* get rounds */
+	pw_crypt->iter_count = SHA256_DEFAULT_ROUNDS;
+	if (strncmp (ptr, sha256_rounds_prefix, sizeof(sha256_rounds_prefix) - 1) == 0) {
+		const char *num = ptr + sizeof(sha256_rounds_prefix) - 1;
+		char *endp;
+		unsigned long int srounds = strtoul (num, &endp, 10);
+		if (*endp == '$') {
+			ptr = endp + 1;
+			pw_crypt->iter_count = (uint32_t)srounds;
+		} else {
+			return -1;
+		}
+	}
+
+	/* get salt */
+	for (tmp = ptr; *tmp != '$'; tmp++) {
+		if (tmp == '\0')
+			return -1;
+		count++;
+	}
+	count = MIN(count, SHA256_SALT_MAX);
+	memcpy (pw_crypt->salt, ptr, count);
+	pw_crypt->salt_size = count;
+	ptr = tmp + 1;
+
+	/* get hash */
+	if (strlen(ptr) < SHA256_B64_LENGTH)
+		return -1;
+	b64_hash = malloc (SHA256_B64_LENGTH + 1);
+	if (!b64_hash)
+		return -1;
+	memcpy (b64_hash, ptr, SHA256_B64_LENGTH);
+	b64_hash[SHA256_B64_LENGTH] = '\0';
+
+	if (restore_sha256_array (b64_hash, pw_crypt->hash) < 0)
+		return -1;
+
+	free (b64_hash);
+
+	return 0;
+}
+
+int
+decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt)
+{
+	if (!pw_crypt)
+		return -1;
+
+	if (strncmp (crypt_pass, sha256_prefix, 3) == 0) {
+		pw_crypt->method = SHA256_BASED;
+		return decode_sha256_pass (crypt_pass + 3, pw_crypt);
+	}
+
+	return -1;
+}
+
+char
+int_to_b64 (const int i)
+{
+	return b64t[i & 0x3f];
+}
+
+int
+b64_to_int (const char c)
+{
+	if (c == '.')
+		return 0;
+
+	if (c == '/')
+		return 1;
+
+	if (c >= '0' && c <= '9')
+		return (c - '0' + 2);
+
+	if (c >= 'A' && c <= 'Z')
+		return (c - 'A' + 12);
+
+	if (c >= 'a' && c <= 'z')
+		return (c - 'a' + 38);
+
+	return -1;
+}
+
+static int
+split_24bit (const char *string, uint8_t *hash, int start, int n,
+	     uint32_t b2, uint32_t b1, uint32_t b0)
+{
+	uint32_t tmp = 0;
+	int i, value;
+
+	for (i = start; i < start + n; i++) {
+		value = b64_to_int (string[i]);
+		if (value < 0)
+			return -1;
+		tmp |= value << (6*(i - start));
+	}
+
+	hash[b0] = (uint8_t)(tmp & 0xff);
+	hash[b1] = (uint8_t)((tmp >> 8) & 0xff);
+	hash[b2] = (uint8_t)((tmp >> 16) & 0xff);
+
+	return 0;
+}
+
+int
+restore_sha256_array (const char *string, uint8_t *hash)
+{
+	uint32_t tmp = 0;
+	int i, value;
+
+	if (strlen (string) != SHA256_B64_LENGTH)
+		return -1;
+
+	if (split_24bit (string, hash,  0, 4, 0, 10, 20) < 0)
+		return -1;
+	if (split_24bit (string, hash,  4, 4, 21, 1, 11) < 0)
+		return -1;
+	if (split_24bit (string, hash,  8, 4, 12, 22, 2) < 0)
+		return -1;
+	if (split_24bit (string, hash, 12, 4, 3, 13, 23) < 0)
+		return -1;
+	if (split_24bit (string, hash, 16, 4, 24, 4, 14) < 0)
+		return -1;
+	if (split_24bit (string, hash, 20, 4, 15, 25, 5) < 0)
+		return -1;
+	if (split_24bit (string, hash, 24, 4, 6, 16, 26) < 0)
+		return -1;
+	if (split_24bit (string, hash, 28, 4, 27, 7, 17) < 0)
+		return -1;
+	if (split_24bit (string, hash, 32, 4, 18, 28, 8) < 0)
+		return -1;
+	if (split_24bit (string, hash, 36, 4, 9, 19, 29) < 0)
+		return -1;
+
+	for (i = 40; i < 43 ; i++) {
+		value = b64_to_int (string[i]);
+		if (value < 0)
+			return -1;
+		tmp |= value << (6*(i - 40));
+	}
+
+	hash[30] = (uint8_t)(tmp & 0xff);
+	hash[31] = (uint8_t)((tmp >> 8) & 0xff);
+
+	return 0;
+}
+
+
diff --git a/src/password-crypt.h b/src/password-crypt.h
new file mode 100644
index 0000000..149a05e
--- /dev/null
+++ b/src/password-crypt.h
@@ -0,0 +1,42 @@
+#ifndef __PASSWORD_CRYPT_H__
+#define __PASSWORD_CRYPT_H__
+
+#include <stdint.h>
+
+/* The max salt size (in characters [./0-9A-Za-z]) */
+#define T_DES_SALT_MAX 2
+#define E_BSI_DES_SALT_MAX 4
+#define MD5_SALT_MAX 8
+#define SHA256_SALT_MAX 16
+#define SHA512_SALT_MAX 16
+/* The max salt size of Blowfish in UINT8 */
+#define BLOWFISH_SALT_MAX 16
+
+enum HashMethod {
+	TRANDITIONAL_DES = 0,
+	EXTEND_BSDI_DES,
+	MD5_BASED,
+	SHA256_BASED,
+	SHA512_BASED,
+	BLOWFISH_BASED
+};
+
+typedef struct {
+	uint16_t method;
+	uint64_t iter_count;
+	uint16_t salt_size;
+	uint8_t  salt[32];
+	uint8_t  hash[128];
+} __attribute__ ((packed)) pw_crypt_t;
+
+#define PASSWORD_CRYPT_SIZE sizeof(pw_crypt_t)
+
+#define SHA256_B64_LENGTH 43
+
+int get_hash_size (int method);
+const char *get_crypt_prefix (int method);
+int decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt);
+char int_to_b64 (const int i);
+int b64_to_int (const char c);
+
+#endif /* __PASSWORD_CRYPT_H__ */
-- 
1.7.10.4


From 80ddd5d426e96d251f53bf5653a3bd20aebb32ab Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Thu, 24 Jan 2013 18:37:33 +0800
Subject: [PATCH 2/9] Support SHA512-based crypt_r() hash

---
 src/mokutil.c        |   23 ++++++---
 src/password-crypt.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/password-crypt.h |    1 +
 3 files changed, 140 insertions(+), 11 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index f71cb6a..d1c3763 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -43,8 +43,9 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b,
 #define HASH_FILE          0x4000
 #define GENERATE_PW_HASH   0x8000
 
-#define DEFAULT_CRYPT_METHOD SHA256_BASED
-#define DEFAULT_SALT_SIZE    SHA256_SALT_MAX
+#define DEFAULT_CRYPT_METHOD SHA512_BASED
+#define DEFAULT_SALT_SIZE    SHA512_SALT_MAX
+#define SETTINGS_LEN         (DEFAULT_SALT_SIZE*2)
 
 typedef struct {
 	uint32_t mok_size;
@@ -384,7 +385,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len)
 {
 	pw_crypt_t new_crypt;
 	struct crypt_data data;
-	char settings[64];
+	char settings[SETTINGS_LEN];
 	char *crypt_string;
 	const char *prefix;
 	int hash_len, prefix_len;
@@ -1033,9 +1034,11 @@ static int
 generate_pw_hash (const char *input_pw)
 {
 	struct crypt_data data;
-	char settings[SHA256_SALT_MAX + 3 + 1];
+	char settings[SETTINGS_LEN];
 	char *password = NULL;
 	char *crypt_string;
+	const char *prefix;
+	int prefix_len;
 	int pw_len, ret = -1;
 
 	if (input_pw) {
@@ -1058,9 +1061,15 @@ generate_pw_hash (const char *input_pw)
 		}
 	}
 
-	strncpy (settings, "$5$", 3);
-	generate_salt ((uint8_t *)(settings + 3), SHA256_SALT_MAX, 0);
-	settings[SHA256_SALT_MAX + 3] = '\0';
+	prefix = get_crypt_prefix (DEFAULT_CRYPT_METHOD);
+	if (!prefix)
+		return -1;
+	prefix_len = strlen(prefix);
+
+	strncpy (settings, prefix, prefix_len);
+	generate_salt ((uint8_t *)(settings + prefix_len),
+		       DEFAULT_SALT_SIZE, DEFAULT_SALT_SIZE);
+	settings[DEFAULT_SALT_SIZE + prefix_len] = '\0';
 
 	crypt_string = crypt_r (password, settings, &data);
 	if (!crypt_string) {
diff --git a/src/password-crypt.c b/src/password-crypt.c
index f004049..84ee079 100644
--- a/src/password-crypt.c
+++ b/src/password-crypt.c
@@ -7,6 +7,7 @@
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
 #define SHA256_DEFAULT_ROUNDS 5000
+#define SHA512_DEFAULT_ROUNDS 5000
 
 static const char b64t[64] =
 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -14,9 +15,10 @@ static const char b64t[64] =
 static const char sha256_prefix[] = "$5$";
 static const char sha512_prefix[] = "$6$";
 
-static const char sha256_rounds_prefix[] = "rounds=";
+static const char sha_rounds_prefix[] = "rounds=";
 
 static int restore_sha256_array (const char *string, uint8_t *hash);
+static int restore_sha512_array (const char *string, uint8_t *hash);
 
 int
 get_hash_size (int method)
@@ -70,8 +72,8 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt)
 
 	/* get rounds */
 	pw_crypt->iter_count = SHA256_DEFAULT_ROUNDS;
-	if (strncmp (ptr, sha256_rounds_prefix, sizeof(sha256_rounds_prefix) - 1) == 0) {
-		const char *num = ptr + sizeof(sha256_rounds_prefix) - 1;
+	if (strncmp (ptr, sha_rounds_prefix, sizeof(sha_rounds_prefix) - 1) == 0) {
+		const char *num = ptr + sizeof(sha_rounds_prefix) - 1;
 		char *endp;
 		unsigned long int srounds = strtoul (num, &endp, 10);
 		if (*endp == '$') {
@@ -110,6 +112,56 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt)
 	return 0;
 }
 
+static int
+decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt)
+{
+	/* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{86} */
+	char *tmp, *ptr = (char *)string;
+	char *b64_hash;
+	int count = 0;
+
+	/* get rounds */
+	pw_crypt->iter_count = SHA512_DEFAULT_ROUNDS;
+	if (strncmp (ptr, sha_rounds_prefix, sizeof(sha_rounds_prefix) - 1) == 0) {
+		const char *num = ptr + sizeof(sha_rounds_prefix) - 1;
+		char *endp;
+		unsigned long int srounds = strtoul (num, &endp, 10);
+		if (*endp == '$') {
+			ptr = endp + 1;
+			pw_crypt->iter_count = (uint32_t)srounds;
+		} else {
+			return -1;
+		}
+	}
+
+	/* get salt */
+	for (tmp = ptr; *tmp != '$'; tmp++) {
+		if (tmp == '\0')
+			return -1;
+		count++;
+	}
+	count = MIN(count, SHA512_SALT_MAX);
+	memcpy (pw_crypt->salt, ptr, count);
+	pw_crypt->salt_size = count;
+	ptr = tmp + 1;
+
+	/* get hash */
+	if (strlen(ptr) < SHA512_B64_LENGTH)
+		return -1;
+	b64_hash = malloc (SHA512_B64_LENGTH + 1);
+	if (!b64_hash)
+		return -1;
+	memcpy (b64_hash, ptr, SHA512_B64_LENGTH);
+	b64_hash[SHA512_B64_LENGTH] = '\0';
+
+	if (restore_sha512_array (b64_hash, pw_crypt->hash) < 0)
+		return -1;
+
+	free (b64_hash);
+
+	return 0;
+}
+
 int
 decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt)
 {
@@ -118,7 +170,12 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt)
 
 	if (strncmp (crypt_pass, sha256_prefix, 3) == 0) {
 		pw_crypt->method = SHA256_BASED;
-		return decode_sha256_pass (crypt_pass + 3, pw_crypt);
+		return decode_sha256_pass (crypt_pass + strlen (sha256_prefix), pw_crypt);
+	}
+
+	if (strncmp (crypt_pass, sha512_prefix, 3) == 0) {
+		pw_crypt->method = SHA512_BASED;
+		return decode_sha512_pass (crypt_pass + strlen (sha512_prefix), pw_crypt);
 	}
 
 	return -1;
@@ -215,4 +272,66 @@ restore_sha256_array (const char *string, uint8_t *hash)
 	return 0;
 }
 
+int
+restore_sha512_array (const char *string, uint8_t *hash)
+{
+	uint32_t tmp = 0;
+	int value1, value2;
+
+	if (strlen (string) != SHA512_B64_LENGTH)
+		return -1;
+
+	if (split_24bit (string, hash,  0, 4, 0, 21, 42) < 0)
+		return -1;
+	if (split_24bit (string, hash,  4, 4, 22, 43, 1) < 0)
+		return -1;
+	if (split_24bit (string, hash,  8, 4, 44, 2, 23) < 0)
+		return -1;
+	if (split_24bit (string, hash, 12, 4, 3, 24, 45) < 0)
+		return -1;
+	if (split_24bit (string, hash, 16, 4, 25, 46, 4) < 0)
+		return -1;
+	if (split_24bit (string, hash, 20, 4, 47, 5, 26) < 0)
+		return -1;
+	if (split_24bit (string, hash, 24, 4, 6, 27, 48) < 0)
+		return -1;
+	if (split_24bit (string, hash, 28, 4, 28, 49, 7) < 0)
+		return -1;
+	if (split_24bit (string, hash, 32, 4, 50, 8, 29) < 0)
+		return -1;
+	if (split_24bit (string, hash, 36, 4, 9, 30, 51) < 0)
+		return -1;
+	if (split_24bit (string, hash, 40, 4, 31, 52, 10) < 0)
+		return -1;
+	if (split_24bit (string, hash, 44, 4, 53, 11, 32) < 0)
+		return -1;
+	if (split_24bit (string, hash, 48, 4, 12, 33, 54) < 0)
+		return -1;
+	if (split_24bit (string, hash, 52, 4, 34, 55, 13) < 0)
+		return -1;
+	if (split_24bit (string, hash, 56, 4, 56, 14, 35) < 0)
+		return -1;
+	if (split_24bit (string, hash, 60, 4, 15, 36, 57) < 0)
+		return -1;
+	if (split_24bit (string, hash, 64, 4, 37, 58, 16) < 0)
+		return -1;
+	if (split_24bit (string, hash, 68, 4, 59, 17, 38) < 0)
+		return -1;
+	if (split_24bit (string, hash, 72, 4, 18, 39, 60) < 0)
+		return -1;
+	if (split_24bit (string, hash, 76, 4, 40, 61, 19) < 0)
+		return -1;
+	if (split_24bit (string, hash, 80, 4, 62, 20, 41) < 0)
+		return -1;
+
+	value1 = b64_to_int (string[85]);
+	if (value1 < 0)
+		return -1;
+	value2 = b64_to_int (string[84]);
+	if (value2 < 0)
+		return -1;
+	tmp = (value1 << 6) | value2;
+	hash[63] = (uint8_t)tmp;
 
+	return 0;
+}
diff --git a/src/password-crypt.h b/src/password-crypt.h
index 149a05e..a1f7710 100644
--- a/src/password-crypt.h
+++ b/src/password-crypt.h
@@ -32,6 +32,7 @@ typedef struct {
 #define PASSWORD_CRYPT_SIZE sizeof(pw_crypt_t)
 
 #define SHA256_B64_LENGTH 43
+#define SHA512_B64_LENGTH 86
 
 int get_hash_size (int method);
 const char *get_crypt_prefix (int method);
-- 
1.7.10.4


From 032018daddfe6bca086c5ef1f79d147e3ac0b02a Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 25 Jan 2013 14:22:02 +0800
Subject: [PATCH 3/9] Add the new option to import root password hash

---
 src/mokutil.c |   78 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 63 insertions(+), 15 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index d1c3763..006eff1 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -7,6 +7,7 @@
 #include <unistd.h>
 #include <termios.h>
 #include <getopt.h>
+#include <shadow.h>
 
 #include <openssl/sha.h>
 #include <openssl/x509.h>
@@ -42,6 +43,7 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b,
 #define RESET              0x2000
 #define HASH_FILE          0x4000
 #define GENERATE_PW_HASH   0x8000
+#define ROOT_PW            0x10000
 
 #define DEFAULT_CRYPT_METHOD SHA512_BASED
 #define DEFAULT_SALT_SIZE    SHA512_SALT_MAX
@@ -83,6 +85,9 @@ print_help ()
 	printf ("  --hash-file <hash file>\t\tUse the specific password hash\n");
 	printf ("                         \t\t(Only valid with --import, --delete,\n");
 	printf ("                         \t\t --password, and --reset)\n");
+	printf ("  --root-pw\t\t\t\tUse the root password\n");
+	printf ("           \t\t\t\t(Only valid with --import, --delete,\n");
+	printf ("           \t\t\t\t --password, and --reset)\n");
 }
 
 static int
@@ -448,8 +453,23 @@ get_hash_from_file (const char *file, pw_crypt_t *pw_crypt)
 }
 
 static int
+get_password_from_shadow (pw_crypt_t *pw_crypt)
+{
+	struct spwd *pw_ent;
+
+	pw_ent = getspnam ("root");
+	if (!pw_ent)
+		return -1;
+
+	if (decode_pass (pw_ent->sp_pwdp, pw_crypt) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int
 update_request (void *new_list, int list_len, uint8_t import,
-		const char *hash_file)
+		const char *hash_file, const int root_pw)
 {
 	efi_variable_t var;
 	const char *req_name, *auth_name;
@@ -474,6 +494,11 @@ update_request (void *new_list, int list_len, uint8_t import,
 			fprintf (stderr, "Failed to read hash\n");
 			goto error;
 		}
+	} else if (root_pw) {
+		if (get_password_from_shadow (&pw_crypt) < 0) {
+			fprintf (stderr, "Failed to get root password hash\n");
+			goto error;
+		}
 	} else {
 		if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) {
 			fprintf (stderr, "Abort\n");
@@ -618,7 +643,7 @@ is_valid_request (void *mok, uint32_t mok_size, uint8_t import)
 
 static int
 issue_mok_request (char **files, uint32_t total, uint8_t import,
-		   const char *hash_file)
+		   const char *hash_file, const int root_pw)
 {
 	efi_variable_t old_req;
 	const char *req_name;
@@ -731,7 +756,7 @@ issue_mok_request (char **files, uint32_t total, uint8_t import,
 		real_size += old_req.DataSize;
 	}
 
-	if (update_request (new_list, real_size, import, hash_file) < 0) {
+	if (update_request (new_list, real_size, import, hash_file, root_pw) < 0) {
 		goto error;
 	}
 
@@ -748,15 +773,17 @@ error:
 }
 
 static int
-import_moks (char **files, uint32_t total, const char *hash_file)
+import_moks (char **files, uint32_t total, const char *hash_file,
+	     const int root_pw)
 {
-	return issue_mok_request (files, total, 1, hash_file);
+	return issue_mok_request (files, total, 1, hash_file, root_pw);
 }
 
 static int
-delete_moks (char **files, uint32_t total, const char *hash_file)
+delete_moks (char **files, uint32_t total, const char *hash_file,
+	     const int root_pw)
 {
-	return issue_mok_request (files, total, 0, hash_file);
+	return issue_mok_request (files, total, 0, hash_file, root_pw);
 }
 
 static int
@@ -832,7 +859,7 @@ error:
 }
 
 static int
-set_password (const char *hash_file)
+set_password (const char *hash_file, const int root_pw)
 {
 	efi_variable_t var;
 	pw_crypt_t pw_crypt;
@@ -848,6 +875,11 @@ set_password (const char *hash_file)
 			fprintf (stderr, "Failed to read hash\n");
 			goto error;
 		}
+	} else if (root_pw) {
+		if (get_password_from_shadow (&pw_crypt) < 0) {
+			fprintf (stderr, "Failed to get root password hash\n");
+			goto error;
+		}
 	} else {
 		if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) {
 			fprintf (stderr, "Abort\n");
@@ -1020,9 +1052,9 @@ error:
 }
 
 static int
-reset_moks (const char *hash_file)
+reset_moks (const char *hash_file, const int root_pw)
 {
-	if (update_request (NULL, 0, 1, hash_file)) {
+	if (update_request (NULL, 0, 1, hash_file, root_pw)) {
 		fprintf (stderr, "Failed to issue a reset request\n");
 		return -1;
 	}
@@ -1117,11 +1149,12 @@ main (int argc, char *argv[])
 			{"reset",              no_argument,       0, 0  },
 			{"hash-file",          required_argument, 0, 'f'},
 			{"generate-hash",      optional_argument, 0, 'g'},
+			{"root-pw",            no_argument,       0, 'P'},
 			{0, 0, 0, 0}
 		};
 
 		int option_index = 0;
-		c = getopt_long (argc, argv, "d:f:g::hi:pt:x",
+		c = getopt_long (argc, argv, "d:f:g::hi:pt:xP",
 				 long_options, &option_index);
 
 		if (c == -1)
@@ -1189,6 +1222,9 @@ main (int argc, char *argv[])
 		case 'p':
 			command |= PASSWORD;
 			break;
+		case 'P':
+			command |= ROOT_PW;
+			break;
 		case 't':
 			key_file = strdup (optarg);
 
@@ -1215,11 +1251,17 @@ main (int argc, char *argv[])
 			break;
 		case IMPORT:
 		case IMPORT | HASH_FILE:
-			ret = import_moks (files, total, hash_file);
+			ret = import_moks (files, total, hash_file, 0);
+			break;
+		case IMPORT | ROOT_PW:
+			ret = import_moks (files, total, NULL, 1);
 			break;
 		case DELETE:
 		case DELETE | HASH_FILE:
-			ret = delete_moks (files, total, hash_file);
+			ret = delete_moks (files, total, hash_file, 0);
+			break;
+		case DELETE | ROOT_PW:
+			ret = delete_moks (files, total, NULL, 1);
 			break;
 		case REVOKE_IMPORT:
 			ret = revoke_request (1);
@@ -1232,7 +1274,10 @@ main (int argc, char *argv[])
 			break;
 		case PASSWORD:
 		case PASSWORD | HASH_FILE:
-			ret = set_password (hash_file);
+			ret = set_password (hash_file, 0);
+			break;
+		case PASSWORD | ROOT_PW:
+			ret = set_password (NULL, 1);
 			break;
 		case DISABLE_VALIDATION:
 			ret = disable_validation ();
@@ -1248,7 +1293,10 @@ main (int argc, char *argv[])
 			break;
 		case RESET:
 		case RESET | HASH_FILE:
-			ret = reset_moks (hash_file);
+			ret = reset_moks (hash_file, 0);
+			break;
+		case RESET | ROOT_PW:
+			ret = reset_moks (NULL, 1);
 			break;
 		case GENERATE_PW_HASH:
 			ret = generate_pw_hash (input_pw);
-- 
1.7.10.4


From 282c97b30c87687e43a019fcde3db8d809f8d227 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Fri, 25 Jan 2013 18:29:06 +0800
Subject: [PATCH 4/9] Support blowfish-based crypt() hash

---
 src/mokutil.c        |   15 +++++++++++++++
 src/password-crypt.c |   48 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/password-crypt.h |    3 +--
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index 006eff1..b6c665d 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -508,10 +508,18 @@ update_request (void *new_list, int list_len, uint8_t import,
 		pw_crypt.salt_size = generate_salt (pw_crypt.salt,
 						    DEFAULT_SALT_SIZE,
 						    DEFAULT_SALT_SIZE);
+
 		if (generate_hash (&pw_crypt, password, pw_len) < 0) {
 			fprintf (stderr, "Couldn't generate hash\n");
 			goto error;
 		}
+		if (pw_crypt.method == BLOWFISH_BASED) {
+			const char *prefix = get_crypt_prefix (BLOWFISH_BASED);
+			memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX);
+			memcpy (pw_crypt.salt, prefix, 7);
+			pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0';
+			pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1;
+		}
 	}
 
 	if (new_list) {
@@ -893,6 +901,13 @@ set_password (const char *hash_file, const int root_pw)
 			fprintf (stderr, "Couldn't generate hash\n");
 			goto error;
 		}
+		if (pw_crypt.method == BLOWFISH_BASED) {
+			const char *prefix = get_crypt_prefix (BLOWFISH_BASED);
+			memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX);
+			memcpy (pw_crypt.salt, prefix, 7);
+			pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0';
+			pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1;
+		}
 	}
 
 	var.Data = (void *)&pw_crypt;
diff --git a/src/password-crypt.c b/src/password-crypt.c
index 84ee079..3ecb6ff 100644
--- a/src/password-crypt.c
+++ b/src/password-crypt.c
@@ -6,6 +6,8 @@
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
+#define BLOWFISH_HASH_SIZE 31 /* 184 / 6 + 1 */
+
 #define SHA256_DEFAULT_ROUNDS 5000
 #define SHA512_DEFAULT_ROUNDS 5000
 
@@ -15,6 +17,10 @@ static const char b64t[64] =
 static const char sha256_prefix[] = "$5$";
 static const char sha512_prefix[] = "$6$";
 
+static const char bf_a_prefix[] = "$2a$";
+static const char bf_x_prefix[] = "$2x$";
+static const char bf_y_prefix[] = "$2y$";
+
 static const char sha_rounds_prefix[] = "rounds=";
 
 static int restore_sha256_array (const char *string, uint8_t *hash);
@@ -35,7 +41,7 @@ get_hash_size (int method)
 	case SHA512_BASED:
 		return SHA512_DIGEST_LENGTH;
 	case BLOWFISH_BASED:
-		return 184 / 8; /* per "man crypt" */
+		return BLOWFISH_HASH_SIZE;
 	}
 
 	return -1;
@@ -56,7 +62,7 @@ get_crypt_prefix (int method)
 	case SHA512_BASED:
 		return "$6$";
 	case BLOWFISH_BASED:
-		return "$2y$"; /* per "man crypt" */
+		return "$2y$10$"; /* FIXME change the count */
 	}
 
 	return NULL;
@@ -162,6 +168,37 @@ decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt)
 	return 0;
 }
 
+static int
+decode_blowfish_pass (const char *string, pw_crypt_t *pw_crypt)
+{
+	/* Expected string: \$2[axy]\$[0-9]{2}\$[./A-Za-z0-9]{53} */
+	/* Store the first (22+7) bytes in salt[] and the rest in hash */
+
+	if (strlen(string) != (53 + 7))
+		return -1;
+
+	if (string[0] != '$' ||
+	    string[1] != '2' ||
+	    (string[2] != 'a' && string[2] != 'x' && string[2] != 'y') ||
+	    string[3] != '$' ||
+	    string[4] < '0' || string[4] > '3' ||
+	    string[5] < '0' || string[5] > '9' ||
+	    (string[4] == '3' && string[5] > '1') ||
+	    string[6] != '$') {
+		return -1;
+        }
+
+	pw_crypt->iter_count = 0;
+
+	memcpy (pw_crypt->salt, string, (22 + 7));
+	pw_crypt->salt[22 + 7] = '\0';
+	pw_crypt->salt_size = 22 + 7 + 1;
+
+	memcpy (pw_crypt->hash, string + 22 + 7, BLOWFISH_HASH_SIZE);
+
+	return 0;
+}
+
 int
 decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt)
 {
@@ -178,6 +215,13 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt)
 		return decode_sha512_pass (crypt_pass + strlen (sha512_prefix), pw_crypt);
 	}
 
+	if (strncmp (crypt_pass, bf_a_prefix, 4) == 0 ||
+	    strncmp (crypt_pass, bf_x_prefix, 4) == 0 ||
+	    strncmp (crypt_pass, bf_y_prefix, 4) == 0) {
+		pw_crypt->method = BLOWFISH_BASED;
+		return decode_blowfish_pass (crypt_pass, pw_crypt);
+	}
+
 	return -1;
 }
 
diff --git a/src/password-crypt.h b/src/password-crypt.h
index a1f7710..701dfd9 100644
--- a/src/password-crypt.h
+++ b/src/password-crypt.h
@@ -9,8 +9,7 @@
 #define MD5_SALT_MAX 8
 #define SHA256_SALT_MAX 16
 #define SHA512_SALT_MAX 16
-/* The max salt size of Blowfish in UINT8 */
-#define BLOWFISH_SALT_MAX 16
+#define BLOWFISH_SALT_MAX 22
 
 enum HashMethod {
 	TRANDITIONAL_DES = 0,
-- 
1.7.10.4


From 97f0dec8aa8f63a7ef81e060a512b13bcdf4e3a7 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Mon, 28 Jan 2013 16:12:44 +0800
Subject: [PATCH 5/9] Simplify the hash generation

---
 src/mokutil.c |   30 +++++++++---------------------
 1 file changed, 9 insertions(+), 21 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index b6c665d..ecf9e00 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -403,6 +403,10 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len)
 		return -1;
 	prefix_len = strlen(prefix);
 
+	pw_crypt->salt_size = generate_salt (pw_crypt->salt,
+					     DEFAULT_SALT_SIZE,
+					     DEFAULT_SALT_SIZE);
+
 	strncpy (settings, prefix, prefix_len);
 	strncpy (settings + prefix_len, (const char *)pw_crypt->salt,
 		 pw_crypt->salt_size);
@@ -421,6 +425,11 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len)
 	memcpy (pw_crypt->hash, new_crypt.hash, hash_len);
 	pw_crypt->iter_count = new_crypt.iter_count;
 
+	if (pw_crypt->method == BLOWFISH_BASED) {
+		pw_crypt->salt_size = new_crypt.salt_size;
+		memcpy (pw_crypt->salt, new_crypt.salt, new_crypt.salt_size);
+	}
+
 	return 0;
 }
 
@@ -505,21 +514,10 @@ update_request (void *new_list, int list_len, uint8_t import,
 			goto error;
 		}
 
-		pw_crypt.salt_size = generate_salt (pw_crypt.salt,
-						    DEFAULT_SALT_SIZE,
-						    DEFAULT_SALT_SIZE);
-
 		if (generate_hash (&pw_crypt, password, pw_len) < 0) {
 			fprintf (stderr, "Couldn't generate hash\n");
 			goto error;
 		}
-		if (pw_crypt.method == BLOWFISH_BASED) {
-			const char *prefix = get_crypt_prefix (BLOWFISH_BASED);
-			memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX);
-			memcpy (pw_crypt.salt, prefix, 7);
-			pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0';
-			pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1;
-		}
 	}
 
 	if (new_list) {
@@ -894,20 +892,10 @@ set_password (const char *hash_file, const int root_pw)
 			goto error;
 		}
 
-		pw_crypt.salt_size = generate_salt (pw_crypt.salt,
-						    DEFAULT_SALT_SIZE,
-						    DEFAULT_SALT_SIZE);
 		if (generate_hash (&pw_crypt, password, pw_len) < 0) {
 			fprintf (stderr, "Couldn't generate hash\n");
 			goto error;
 		}
-		if (pw_crypt.method == BLOWFISH_BASED) {
-			const char *prefix = get_crypt_prefix (BLOWFISH_BASED);
-			memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX);
-			memcpy (pw_crypt.salt, prefix, 7);
-			pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0';
-			pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1;
-		}
 	}
 
 	var.Data = (void *)&pw_crypt;
-- 
1.7.10.4


From 9205203a929aac32fc1e4a53cd8e1c1bb74cfde3 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 29 Jan 2013 12:16:17 +0800
Subject: [PATCH 6/9] Support MD5-based crypt() hash

---
 src/password-crypt.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/password-crypt.h |    1 +
 2 files changed, 77 insertions(+)

diff --git a/src/password-crypt.c b/src/password-crypt.c
index 3ecb6ff..e435ad3 100644
--- a/src/password-crypt.c
+++ b/src/password-crypt.c
@@ -14,6 +14,8 @@
 static const char b64t[64] =
 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
+static const char md5_prefix[] = "$1$";
+
 static const char sha256_prefix[] = "$5$";
 static const char sha512_prefix[] = "$6$";
 
@@ -23,6 +25,7 @@ static const char bf_y_prefix[] = "$2y$";
 
 static const char sha_rounds_prefix[] = "rounds=";
 
+static int restore_md5_array (const char *string, uint8_t *hash);
 static int restore_sha256_array (const char *string, uint8_t *hash);
 static int restore_sha512_array (const char *string, uint8_t *hash);
 
@@ -69,6 +72,39 @@ get_crypt_prefix (int method)
 }
 
 static int
+decode_md5_pass (const char *string, pw_crypt_t *pw_crypt)
+{
+	/* Expected string: [./0-9A-Za-z]{1,8}\$[./0-9A-Za-z]{22} */
+	char *tmp, *ptr = (char *)string;
+	char b64_hash[MD5_B64_LENGTH + 1];
+	int count = 0;
+
+	pw_crypt->iter_count = 1000;
+
+	/* get salt */
+	for (tmp = ptr; *tmp != '$'; tmp++) {
+		if (*tmp == '\0')
+			return -1;
+		count++;
+	}
+	count = MIN(count, MD5_SALT_MAX);
+	memcpy (pw_crypt->salt, ptr, count);
+	pw_crypt->salt_size = count;
+	ptr = tmp + 1;
+
+	/* get hash */
+	if (strlen(ptr) != MD5_B64_LENGTH)
+		return -1;
+	memcpy (b64_hash, ptr, MD5_B64_LENGTH);
+	b64_hash[MD5_B64_LENGTH] = '\0';
+
+	if (restore_md5_array (b64_hash, pw_crypt->hash) < 0)
+		return -1;
+
+	return 0;
+}
+
+static int
 decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt)
 {
 	/* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{43} */
@@ -205,6 +241,11 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt)
 	if (!pw_crypt)
 		return -1;
 
+	if (strncmp (crypt_pass, md5_prefix, 3) == 0) {
+		pw_crypt->method = MD5_BASED;
+		return decode_md5_pass (crypt_pass + strlen (md5_prefix), pw_crypt);
+	}
+
 	if (strncmp (crypt_pass, sha256_prefix, 3) == 0) {
 		pw_crypt->method = SHA256_BASED;
 		return decode_sha256_pass (crypt_pass + strlen (sha256_prefix), pw_crypt);
@@ -273,6 +314,41 @@ split_24bit (const char *string, uint8_t *hash, int start, int n,
 	return 0;
 }
 
+int restore_md5_array (const char *string, uint8_t *hash)
+{
+	uint32_t tmp = 0;
+	int value1, value2;
+
+	if (strlen (string) != MD5_B64_LENGTH)
+		return -1;
+
+	if (split_24bit (string, hash,  0, 4, 0, 6, 12) < 0)
+		return -1;
+
+	if (split_24bit (string, hash,  4, 4, 1, 7, 13) < 0)
+		return -1;
+
+	if (split_24bit (string, hash,  8, 4, 2, 8, 14) < 0)
+		return -1;
+
+	if (split_24bit (string, hash, 12, 4, 3, 9, 15) < 0)
+		return -1;
+
+	if (split_24bit (string, hash, 16, 4, 4, 10, 5) < 0)
+		return -1;
+
+	value1 = b64_to_int (string[21]);
+	if (value1 < 0)
+		return -1;
+	value2 = b64_to_int (string[20]);
+	if (value2 < 0)
+		return -1;
+	tmp = (value1 << 6) | value2;
+	hash[11] = (uint8_t)tmp;
+
+	return 0;
+}
+
 int
 restore_sha256_array (const char *string, uint8_t *hash)
 {
diff --git a/src/password-crypt.h b/src/password-crypt.h
index 701dfd9..aba6975 100644
--- a/src/password-crypt.h
+++ b/src/password-crypt.h
@@ -30,6 +30,7 @@ typedef struct {
 
 #define PASSWORD_CRYPT_SIZE sizeof(pw_crypt_t)
 
+#define MD5_B64_LENGTH 22
 #define SHA256_B64_LENGTH 43
 #define SHA512_B64_LENGTH 86
 
-- 
1.7.10.4


From 472dbeefd87085e4164369110e0ba3d8bf05a964 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 29 Jan 2013 13:59:36 +0800
Subject: [PATCH 7/9] Fix SHA256/SHA512 parsing on hashes with no salt

---
 src/password-crypt.c |   60 +++++++++++++++++++++++++++-----------------------
 1 file changed, 32 insertions(+), 28 deletions(-)

diff --git a/src/password-crypt.c b/src/password-crypt.c
index e435ad3..de15193 100644
--- a/src/password-crypt.c
+++ b/src/password-crypt.c
@@ -109,7 +109,7 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt)
 {
 	/* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{43} */
 	char *tmp, *ptr = (char *)string;
-	char *b64_hash;
+	char b64_hash[SHA256_B64_LENGTH + 1];
 	int count = 0;
 
 	/* get rounds */
@@ -127,30 +127,32 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt)
 	}
 
 	/* get salt */
-	for (tmp = ptr; *tmp != '$'; tmp++) {
-		if (tmp == '\0')
-			return -1;
-		count++;
+	tmp = ptr;
+	if (strlen (ptr) > SHA256_B64_LENGTH) {
+		while (*tmp != '$') {
+			if (tmp == '\0')
+				return -1;
+			count++;
+			tmp++;
+		}
+
+		count = MIN(count, SHA256_SALT_MAX);
+		memcpy (pw_crypt->salt, ptr, count);
+		pw_crypt->salt_size = count;
+		ptr = tmp + 1;
+	} else {
+		pw_crypt->salt_size = 0;
 	}
-	count = MIN(count, SHA256_SALT_MAX);
-	memcpy (pw_crypt->salt, ptr, count);
-	pw_crypt->salt_size = count;
-	ptr = tmp + 1;
 
 	/* get hash */
 	if (strlen(ptr) < SHA256_B64_LENGTH)
 		return -1;
-	b64_hash = malloc (SHA256_B64_LENGTH + 1);
-	if (!b64_hash)
-		return -1;
 	memcpy (b64_hash, ptr, SHA256_B64_LENGTH);
 	b64_hash[SHA256_B64_LENGTH] = '\0';
 
 	if (restore_sha256_array (b64_hash, pw_crypt->hash) < 0)
 		return -1;
 
-	free (b64_hash);
-
 	return 0;
 }
 
@@ -159,7 +161,7 @@ decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt)
 {
 	/* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{86} */
 	char *tmp, *ptr = (char *)string;
-	char *b64_hash;
+	char b64_hash[SHA512_B64_LENGTH + 1];
 	int count = 0;
 
 	/* get rounds */
@@ -177,30 +179,32 @@ decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt)
 	}
 
 	/* get salt */
-	for (tmp = ptr; *tmp != '$'; tmp++) {
-		if (tmp == '\0')
-			return -1;
-		count++;
+	tmp = ptr;
+	if (strlen (ptr) > SHA512_B64_LENGTH) {
+		while (*tmp != '$') {
+			if (tmp == '\0')
+				return -1;
+			count++;
+			tmp++;
+		}
+
+		count = MIN(count, SHA512_SALT_MAX);
+		memcpy (pw_crypt->salt, ptr, count);
+		pw_crypt->salt_size = count;
+		ptr = tmp + 1;
+	} else {
+		pw_crypt->salt_size = 0;
 	}
-	count = MIN(count, SHA512_SALT_MAX);
-	memcpy (pw_crypt->salt, ptr, count);
-	pw_crypt->salt_size = count;
-	ptr = tmp + 1;
 
 	/* get hash */
 	if (strlen(ptr) < SHA512_B64_LENGTH)
 		return -1;
-	b64_hash = malloc (SHA512_B64_LENGTH + 1);
-	if (!b64_hash)
-		return -1;
 	memcpy (b64_hash, ptr, SHA512_B64_LENGTH);
 	b64_hash[SHA512_B64_LENGTH] = '\0';
 
 	if (restore_sha512_array (b64_hash, pw_crypt->hash) < 0)
 		return -1;
 
-	free (b64_hash);
-
 	return 0;
 }
 
-- 
1.7.10.4


From ddd501071734325a213fe994471dac269c69153a Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 29 Jan 2013 16:34:59 +0800
Subject: [PATCH 8/9] Just use crypt() to generate hashes

---
 src/mokutil.c |    7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/src/mokutil.c b/src/mokutil.c
index ecf9e00..27ebf09 100644
--- a/src/mokutil.c
+++ b/src/mokutil.c
@@ -12,7 +12,6 @@
 #include <openssl/sha.h>
 #include <openssl/x509.h>
 
-#define __USE_GNU
 #include <crypt.h>
 
 #include "efi.h"
@@ -389,7 +388,6 @@ static int
 generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len)
 {
 	pw_crypt_t new_crypt;
-	struct crypt_data data;
 	char settings[SETTINGS_LEN];
 	char *crypt_string;
 	const char *prefix;
@@ -412,7 +410,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len)
 		 pw_crypt->salt_size);
 	settings[pw_crypt->salt_size + prefix_len] = '\0';
 
-	crypt_string = crypt_r (password, settings, &data);
+	crypt_string = crypt (password, settings);
 	if (!crypt_string)
 		return -1;
 
@@ -1068,7 +1066,6 @@ reset_moks (const char *hash_file, const int root_pw)
 static int
 generate_pw_hash (const char *input_pw)
 {
-	struct crypt_data data;
 	char settings[SETTINGS_LEN];
 	char *password = NULL;
 	char *crypt_string;
@@ -1106,7 +1103,7 @@ generate_pw_hash (const char *input_pw)
 		       DEFAULT_SALT_SIZE, DEFAULT_SALT_SIZE);
 	settings[DEFAULT_SALT_SIZE + prefix_len] = '\0';
 
-	crypt_string = crypt_r (password, settings, &data);
+	crypt_string = crypt (password, settings);
 	if (!crypt_string) {
 		fprintf (stderr, "Failed to generate hash\n");
 		goto error;
-- 
1.7.10.4


From f944da88acfffe80279de37c4181c9c19ff9a864 Mon Sep 17 00:00:00 2001
From: Gary Ching-Pang Lin <glin@suse.com>
Date: Tue, 29 Jan 2013 16:35:30 +0800
Subject: [PATCH 9/9] Support Traditional DES hash

---
 src/password-crypt.c |   29 +++++++++++++++++++++++++----
 src/password-crypt.h |    2 +-
 2 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/src/password-crypt.c b/src/password-crypt.c
index de15193..95bb687 100644
--- a/src/password-crypt.c
+++ b/src/password-crypt.c
@@ -6,6 +6,8 @@
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
+#define TRAD_DES_HASH_SIZE 13 /* (64/6+1) + (12/6) */
+#define BSDI_DES_HASH_SIZE 20 /* (64/6+1) + (24/6) + 4 + 1 */
 #define BLOWFISH_HASH_SIZE 31 /* 184 / 6 + 1 */
 
 #define SHA256_DEFAULT_ROUNDS 5000
@@ -33,10 +35,10 @@ int
 get_hash_size (int method)
 {
 	switch (method) {
-	case TRANDITIONAL_DES:
-		return 64 / 8; /* per "man crypt" */
+	case TRADITIONAL_DES:
+		return TRAD_DES_HASH_SIZE;
 	case EXTEND_BSDI_DES:
-		return 64 / 8; /* per "man crypt" */
+		return BSDI_DES_HASH_SIZE;
 	case MD5_BASED:
 		return MD5_DIGEST_LENGTH;
 	case SHA256_BASED:
@@ -54,7 +56,7 @@ const char *
 get_crypt_prefix (int method)
 {
 	switch (method) {
-	case TRANDITIONAL_DES:
+	case TRADITIONAL_DES:
 		return ""; /* per "man crypt" */
 	case EXTEND_BSDI_DES:
 		return "_"; /* per "man crypt" */
@@ -72,6 +74,20 @@ get_crypt_prefix (int method)
 }
 
 static int
+decode_trad_des_pass (const char *string, pw_crypt_t *pw_crypt)
+{
+	/* Expected string: [./0-9A-Za-z]{13} */
+	pw_crypt->iter_count = 25;
+	pw_crypt->salt_size = 2;
+	memcpy (pw_crypt->salt, string, 2);
+	pw_crypt->salt[2] = '\0';
+	memcpy (pw_crypt->hash, string, TRAD_DES_HASH_SIZE);
+	pw_crypt->hash[TRAD_DES_HASH_SIZE] = '\0';
+
+	return 0;
+}
+
+static int
 decode_md5_pass (const char *string, pw_crypt_t *pw_crypt)
 {
 	/* Expected string: [./0-9A-Za-z]{1,8}\$[./0-9A-Za-z]{22} */
@@ -267,6 +283,11 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt)
 		return decode_blowfish_pass (crypt_pass, pw_crypt);
 	}
 
+	if (strlen (crypt_pass) == TRAD_DES_HASH_SIZE) {
+		pw_crypt->method = TRADITIONAL_DES;
+		return decode_trad_des_pass (crypt_pass, pw_crypt);
+	}
+
 	return -1;
 }
 
diff --git a/src/password-crypt.h b/src/password-crypt.h
index aba6975..92338ad 100644
--- a/src/password-crypt.h
+++ b/src/password-crypt.h
@@ -12,7 +12,7 @@
 #define BLOWFISH_SALT_MAX 22
 
 enum HashMethod {
-	TRANDITIONAL_DES = 0,
+	TRADITIONAL_DES = 0,
 	EXTEND_BSDI_DES,
 	MD5_BASED,
 	SHA256_BASED,
-- 
1.7.10.4

openSUSE Build Service is sponsored by