From c5d08b63d47db48bd239599f8fb53b13f879e1ff Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin 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 - -#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 #include +#define __USE_GNU +#include + #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 \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 \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 +#include +#include +#include +#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 + +/* 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 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 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 #include #include +#include #include #include @@ -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 \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 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 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 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 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 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 #include -#define __USE_GNU #include #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 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