Project

General

Profile

Feature #1743 ยป lighttpd-crypt-md5-ntlm.patch

Patch to add support for the CRYPT-MD5-NTLM password hashing algorithm - Anonymous, 2008-08-05 18:19

View differences:

src/http_auth.c (working copy)
33 33
#include "sys-files.h"
34 34

  
35 35
#ifdef USE_OPENSSL
36
# include <openssl/md4.h>
36 37
# include <openssl/md5.h>
37 38
#else
38 39
# include "md5.h"
......
593 594
    apr_cpystrn(result, passwd, nbytes - 1);
594 595
}
595 596

  
597
/*
598
 * The following is an implementation of the CRYPT-MD5-NTLM password hashing
599
 * algorithm defined as:
600
 *
601
 *   relabel(crypt_md5(lc_hex(ntlm_hash(p))))
602
 *
603
 * where p is the password to hash. IOW the standard MD5-based "$1$" crypt() is
604
 * applied to the lowercase hexadecimal representation of the NTLM hash of the
605
 * password, and the "$1$" label is replaced with "$1+ntml$".
606
 *
607
 * This algorithm allows for the construction of secure, salted password hashes
608
 * from an environment where only legacy NTLM hashes are available and where it
609
 * is not feasible to re-hash all the passwords with the MD5-based crypt().
610
 */
596 611

  
612
#define CRYPT_MD5_NTLM_ID "$1+ntlm$"
613

  
614
#ifdef USE_OPENSSL && HAVE_CRYPT /* CRYPT-MD5-NTLM needs OpenSSL's MD4 and crypt() */
615

  
597 616
/**
617
 * Computes the NTLM hash of the given password.
598 618
 *
619
 * @param pw    password-string to be hashed
620
 * @param out   the binary representation of the hash is stored in this buffer,
621
 *              which must have space for 16 bytes
622
 * @return 0 on success, or -1 on error
623
 */
624
static int ntlm_hash(const char *pw, unsigned char *out) {
625
   char *pw_ucs2le = NULL;
626
   size_t pw_size;
627
   int i;
628
   MD4_CTX c;
629

  
630
   /* encode the pw using UCS-2LE */
631
   if ((pw_size = strlen(pw) * 2))
632
   {
633
      if (!(pw_ucs2le = malloc(pw_size))) {
634
         fprintf(stderr, "%s.%d: malloc failed: %s\n", __FILE__, __LINE__, strerror(errno));
635
         return -1;
636
      }
637
      for (i = 0; i < strlen(pw); i++)
638
      {
639
         pw_ucs2le[(i * 2)] = pw[i];
640
         pw_ucs2le[(i * 2) + 1] = 0;
641
      }
642
   }
643
   /* MD4 the pw */
644
   MD4_Init(&c);
645
   if (pw_ucs2le)
646
      MD4_Update(&c, pw_ucs2le, pw_size);
647
   MD4_Final(out, &c);
648
   /* clean up */
649
   if (pw_ucs2le)
650
      free(pw_ucs2le);
651
   return 0;
652
}
653

  
654
/**
655
 * @return 0 on success, or -1 on error
656
 */
657
static int crypt_md5_ntlm_encode(const char *pw, const char *salt, char *result, size_t nbytes) {
658
   unsigned char nthash[16];
659
   int i;
660
   char hex[sizeof (nthash) * 2 + 1];
661
   char *dollar = NULL;
662
   int salt_len;
663
   char tmp_salt[12]; /* "$1$" + 8 chars + NUL */
664
   char *s;
665

  
666
   /* ntlm hash */
667
   if (ntlm_hash(pw, nthash))
668
      return -1;
669
   /* lowercase hex */
670
   for (i = 0; i < sizeof (nthash); i++)
671
      sprintf(hex + i * 2, "%02x", nthash[i]);
672
   /* crypt */
673
   if (!(dollar = strchr(salt + strlen(CRYPT_MD5_NTLM_ID), '$'))) {
674
      fprintf(stderr, "%s.%d: invalid salt: %s\n", __FILE__, __LINE__, salt);
675
      return -1;
676
   }
677
   salt_len = dollar - (salt + strlen(CRYPT_MD5_NTLM_ID));
678
   snprintf(tmp_salt, sizeof (tmp_salt), "$1$%.*s", salt_len, salt + strlen(CRYPT_MD5_NTLM_ID));
679
   s = crypt(hex, tmp_salt);
680
   if (!s) {
681
      fprintf(stderr, "%s.%d: crypt failed\n", __FILE__, __LINE__);
682
      return -1;
683
   }
684
   /* relabel */
685
   if (strncmp(s, "$1$", 3)) {
686
      fprintf(stderr, "%s.%d: unexpected return value from crypt(): %s\n", __FILE__, __LINE__, s);
687
      return -1;
688
   }
689
   snprintf(result, nbytes, "%s%s", CRYPT_MD5_NTLM_ID, s + 3);
690
   return 0;
691
}
692
#endif
693

  
694
/**
599 695
 *
696
 *
600 697
 * @param password password-string from the auth-backend
601 698
 * @param pw       password-string from the client
602 699
 */
......
637 734
			 */
638 735
			apr_md5_encode(pw, password->ptr, sample, sizeof(sample));
639 736
			return (strcmp(sample, password->ptr) == 0) ? 0 : 1;
737
		} else if (!strncmp(password->ptr, CRYPT_MD5_NTLM_ID, strlen(CRYPT_MD5_NTLM_ID))) {
738
			/*
739
			 * The hash was created using the $1+ntlm$ custom algorithm.
740
			 */
741
#ifdef USE_OPENSSL && HAVE_CRYPT
742
			if (crypt_md5_ntlm_encode(pw, password->ptr, sample, sizeof(sample)))
743
            return -1;
744
			return !!strcmp(sample, password->ptr);
745
#endif
640 746
		} else {
641 747
#ifdef HAVE_CRYPT
642 748
		char salt[32];
    (1-1/1)