mokutil/mokutil-support-crypt-hash-methods.patch

1912 lines
51 KiB
Diff
Raw Normal View History

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