Add sha256/512 support to libcrypt, change default
authorNolan Lum <nol888@gmail.com>
Wed, 1 Dec 2010 21:49:53 +0000 (16:49 -0500)
committerAlex Hornung <ahornung@gmail.com>
Fri, 3 Dec 2010 14:23:51 +0000 (14:23 +0000)
* Add sha256 and sha512 support to libcrypt.

* Change the default password hash to sha256.

* All old passwords will of course still works, but all new ones will be
  created using sha256.

Sponsored-by: Google Code-In
etc/login.conf
lib/libcrypt/Makefile
lib/libcrypt/crypt-sha256.c [new file with mode: 0644]
lib/libcrypt/crypt-sha512.c [new file with mode: 0644]
lib/libcrypt/crypt.3
lib/libcrypt/crypt.c
lib/libcrypt/crypt.h
lib/pam_module/pam_unix/pam_unix.c

index 794c733..2310e98 100644 (file)
@@ -19,7 +19,7 @@
 # Note that entries like "cputime" set both "cputime-cur" and "cputime-max"
 
 default:\
-       :passwd_format=md5:\
+       :passwd_format=sha256:\
        :copyright=/etc/COPYRIGHT:\
        :welcome=/etc/motd:\
        :setenv=MAIL=/var/mail/$,BLOCKSIZE=K,FTP_PASSIVE_MODE=YES:\
index 9e590a0..20c2599 100644 (file)
@@ -7,7 +7,8 @@ SHLIB_MAJOR=    3
 LIB=           crypt
 
 .PATH:         ${.CURDIR}/../libmd
-SRCS=          crypt.c crypt-md5.c md5c.c misc.c
+SRCS=          crypt.c crypt-md5.c crypt-sha256.c crypt-sha512.c \
+            md5c.c sha256c.c sha512c.c misc.c
 WARNS?=                2
 MAN=           crypt.3
 MLINKS=                crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3
@@ -24,7 +25,9 @@ CFLAGS+=      -I${.CURDIR} -DHAS_DES -DHAS_BLOWFISH
 .PATH:         ${.CURDIR}/../libutil
 SRCS+=         auth.c property.c
 .for sym in MD5Init MD5Final MD5Update MD5Pad auth_getval \
-           property_find properties_read properties_free
+           property_find properties_read properties_free \
+           SHA256_Init SHA256_Update SHA256_Final \
+           SHA512_Init SHA512_Update SHA512_Final
 CFLAGS+=       -D${sym}=__${sym}
 .endfor
 PRECIOUSLIB=   yes
diff --git a/lib/libcrypt/crypt-sha256.c b/lib/libcrypt/crypt-sha256.c
new file mode 100644 (file)
index 0000000..ce50c57
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010
+ *     The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Nolan Lum <nol888@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <sha256.h>
+#include "crypt.h"
+
+/*
+ * New password crypt.
+ */
+char*
+crypt_sha256(const char *pw, const char *salt)
+{
+       static const char *magic = "$3$"; /* Magic string for this
+                                                                                * algorithm. Easier to change
+                                                                                * when factored as constant.
+                                                                                */
+       static char         passwd[120], *p;
+       static const char *sp, *ep;
+       unsigned char final[SHA256_SIZE];
+       int sl;
+       SHA256_CTX ctx;
+       unsigned long l;
+
+       /* Refine the salt. */
+       sp = salt;
+
+       /* If it starts with the magic string, then skip that. */
+       if (!strncmp(sp, magic, strlen(magic)))
+               sp += strlen(magic);
+
+       /* Stop at the first '$', max 8 chars. */
+       for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
+               continue;
+
+       /* Get the actual salt length. */
+       sl = ep - sp;
+       
+       SHA256_Init(&ctx);
+       
+       /* Hash in the password first. */
+       SHA256_Update(&ctx, pw, strlen(pw));
+       
+       /* Then the magic string */
+       SHA256_Update(&ctx, magic, sizeof(magic));
+       
+       /* Then the raw salt. */
+       SHA256_Update(&ctx, sp, sl);
+       
+       /* Finish and create the output string. */
+       SHA256_Final(final, &ctx);
+       strcpy(passwd, magic);
+       strncat(passwd, sp, sl);
+       strcat(passwd, "$");
+       
+       p = passwd + strlen(passwd);
+       
+       l = (final[ 0] << 16) | (final[11] << 8) | final[21];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 1] << 16) | (final[12] << 8) | final[22];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 2] << 16) | (final[13] << 8) | final[23];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 3] << 16) | (final[14] << 8) | final[24];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 4] << 16) | (final[15] << 8) | final[25];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 5] << 16) | (final[16] << 8) | final[26];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 6] << 16) | (final[17] << 8) | final[27];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 7] << 16) | (final[18] << 8) | final[28];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 8] << 16) | (final[19] << 8) | final[29];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[ 9] << 16) | (final[20] << 8) | final[30];
+       _crypt_to64(p, l, 4); p += 4;
+       l = (final[10] << 16) | (final[31] << 8);
+       _crypt_to64(p, l, 4); p += 4;
+       *p = '\0';
+       
+       /* Clear memory. */
+       memset(final, 0, sizeof(final));
+       
+       return (passwd);
+}
diff --git a/lib/libcrypt/crypt-sha512.c b/lib/libcrypt/crypt-sha512.c
new file mode 100644 (file)
index 0000000..6b58a28
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010
+ *     The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Nolan Lum <nol888@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <sha512.h>
+#include "crypt.h"
+
+/*
+ * New password crypt.
+ */
+char*
+crypt_sha512(const char *pw, const char *salt)
+{
+       static const char *magic = "$4$"; /* Magic string for this
+                                                                                * algorithm. Easier to change
+                                                                                * when factored as constant.
+                                                                                */
+       static char         passwd[120], *p;
+       static const char *sp, *ep;
+       unsigned char final[SHA512_SIZE];
+       int sl, i;
+       SHA512_CTX ctx;
+       unsigned long l;
+
+       /* Refine the salt. */
+       sp = salt;
+
+       /* If it starts with the magic string, then skip that. */
+       if (!strncmp(sp, magic, strlen(magic)))
+               sp += strlen(magic);
+
+       /* Stop at the first '$', max 8 chars. */
+       for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
+               continue;
+
+       /* Get the actual salt length. */
+       sl = ep - sp;
+       
+       SHA512_Init(&ctx);
+       
+       /* Hash in the password first. */
+       SHA512_Update(&ctx, pw, strlen(pw));
+       
+       /* Then the magic string */
+       SHA512_Update(&ctx, magic, sizeof(magic));
+       
+       /* Then the raw salt. */
+       SHA512_Update(&ctx, sp, sl);
+       
+       /* Finish and create the output string. */
+       SHA512_Final(final, &ctx);
+       strcpy(passwd, magic);
+       strncat(passwd, sp, sl);
+       strcat(passwd, "$");
+       
+       p = passwd + strlen(passwd);
+       
+       /*
+        * For-loop form of the algorithm in sha256.c;
+        * breaks the final output up into 3cols and then base64's each row.
+        */
+       for (i = 0; i < 20; i++) {
+               l = (final[i] << 16) | (final[i + 21] << 8) | final[i + 42];
+               _crypt_to64(p, l, 4); p += 4;
+       }
+       l = (final[20] << 16) | (final[41] << 8);
+       _crypt_to64(p, l, 4); p += 4;
+       *p = '\0';
+       
+       /* Clear memory. */
+       memset(final, 0, sizeof(final));
+       
+       return (passwd);
+}
index f0681b2..a6c8057 100644 (file)
@@ -63,6 +63,8 @@ Currently these include the
 .Tn NBS
 .Tn Data Encryption Standard (DES) ,
 .Tn MD5
+.Tn SHA256
+.Tn SHA512
 and
 .Tn Blowfish .
 The algorithm used will depend upon the format of the Salt (following
@@ -176,6 +178,10 @@ Currently supported algorithms are:
 .It
 MD5
 .It
+SHA256
+.It
+SHA512
+.It
 Blowfish
 .El
 .Pp
@@ -210,7 +216,9 @@ Valid values are
 .\" NOTICE: Also make sure to update this, too, as well
 .\"
 .Ql des ,
-.Ql blf
+.Ql blf ,
+.Ql sha256 ,
+.Ql sha512 ,
 and
 .Ql md5 .
 .Pp
index 4d16ff1..764afab 100644 (file)
@@ -57,6 +57,16 @@ static const struct {
        },
 #endif
        {
+               "sha256",
+               crypt_sha256,
+               "$3$"
+       },
+       {
+               "sha512",
+               crypt_sha512,
+               "$4$"
+       },
+       {
                NULL,
                NULL
        }
index c2f09c0..76c2a4e 100644 (file)
 
 /* magic sizes */
 #define MD5_SIZE 16
+#define SHA256_SIZE 32
+#define SHA512_SIZE 64
 
 char *crypt_des(const char *pw, const char *salt);
 char *crypt_md5(const char *pw, const char *salt);
 char *crypt_blowfish(const char *pw, const char *salt);
+char *crypt_sha256(const char *pw, const char *salt);
+char *crypt_sha512(const char *pw, const char *salt);
 
 extern void _crypt_to64(char *s, unsigned long v, int n);
 
index a2cf30c..b7f1359 100644 (file)
@@ -66,7 +66,7 @@
 #include <security/pam_modules.h>
 #include <security/pam_mod_misc.h>
 
-#define PASSWORD_HASH          "md5"
+#define PASSWORD_HASH          "sha256"
 #define DEFAULT_WARN           (2L * 7L * 86400L)  /* Two weeks */
 #define        SALTSIZE                32