Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

apr1.c

By: a guest on Feb 6th, 2011  |  syntax: C  |  size: 6.83 KB  |  views: 263  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. /*
  2.  * This file is derived from OpenLDAP Software. All of the modifications to
  3.  * OpenLDAP Software represented in the following file were developed by
  4.  * Devin J. Pohly <djpohly@gmail.com>. I have not assigned rights and/or
  5.  * interest in this work to any party.
  6.  *
  7.  * The extensions to OpenLDAP Software herein are subject to the following
  8.  * notice:
  9.  *
  10.  * Copyright 2011 Devin J. Pohly
  11.  * Redistribution and use in source and binary forms, with or without
  12.  * modification, are permitted only as authorized by the OpenLDAP Public
  13.  * License.
  14.  *
  15.  * A portion of this code is used in accordance with the Beer-ware License,
  16.  * revision 42, as noted.
  17.  */
  18. #include <lber.h>
  19. #include <lber_pvt.h>
  20. #include "lutil.h"
  21. #include "lutil_md5.h"
  22. #include <ac/string.h>
  23.  
  24. #include <assert.h>
  25.  
  26. static LUTIL_PASSWD_CHK_FUNC chk_apr1;
  27. static LUTIL_PASSWD_HASH_FUNC hash_apr1;
  28. static const struct berval scheme = BER_BVC("{APR1}");
  29.  
  30. static const unsigned char apr64[] =
  31.         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  32.  
  33. #define APR_SALT_SIZE   8
  34.  
  35. /* copied from liblutil/passwd.c */
  36. static int pw_string64(
  37.         const struct berval *sc,
  38.         const struct berval *hash,
  39.         struct berval *b64,
  40.         const struct berval *salt )
  41. {
  42.         int rc;
  43.         struct berval string;
  44.         size_t b64len;
  45.  
  46.         if( salt ) {
  47.                 /* need to base64 combined string */
  48.                 string.bv_len = hash->bv_len + salt->bv_len;
  49.                 string.bv_val = ber_memalloc( string.bv_len + 1 );
  50.  
  51.                 if( string.bv_val == NULL ) {
  52.                         return LUTIL_PASSWD_ERR;
  53.                 }
  54.  
  55.                 AC_MEMCPY( string.bv_val, hash->bv_val,
  56.                         hash->bv_len );
  57.                 AC_MEMCPY( &string.bv_val[hash->bv_len], salt->bv_val,
  58.                         salt->bv_len );
  59.                 string.bv_val[string.bv_len] = '\0';
  60.  
  61.         } else {
  62.                 string = *hash;
  63.         }
  64.  
  65.         b64len = LUTIL_BASE64_ENCODE_LEN( string.bv_len ) + 1;
  66.         b64->bv_len = b64len + sc->bv_len;
  67.         b64->bv_val = ber_memalloc( b64->bv_len + 1 );
  68.  
  69.         if( b64->bv_val == NULL ) {
  70.                 if( salt ) ber_memfree( string.bv_val );
  71.                 return LUTIL_PASSWD_ERR;
  72.         }
  73.  
  74.         AC_MEMCPY(b64->bv_val, sc->bv_val, sc->bv_len);
  75.  
  76.         rc = lutil_b64_ntop(
  77.                 (unsigned char *) string.bv_val, string.bv_len,
  78.                 &b64->bv_val[sc->bv_len], b64len );
  79.  
  80.         if( salt ) ber_memfree( string.bv_val );
  81.        
  82.         if( rc < 0 ) {
  83.                 return LUTIL_PASSWD_ERR;
  84.         }
  85.  
  86.         /* recompute length */
  87.         b64->bv_len = sc->bv_len + rc;
  88.         assert( strlen(b64->bv_val) == b64->bv_len );
  89.         return LUTIL_PASSWD_OK;
  90. }
  91.  
  92. /* The algorithm implemented in this function was created by Poul-Henning
  93.  * Kamp and released under the following license:
  94.  * ----------------------------------------------------------------------------
  95.  * "THE BEER-WARE LICENSE" (Revision 42):
  96.  * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
  97.  * can do whatever you want with this stuff. If we meet some day, and you think
  98.  * this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp
  99.  * ----------------------------------------------------------------------------
  100.  */
  101. static void do_apr_hash(
  102.         const struct berval *passwd,
  103.         const struct berval *salt,
  104.         unsigned char *digest)
  105. {
  106.         lutil_MD5_CTX ctx, ctx1;
  107.         int n;
  108.  
  109.         /* Start hashing */
  110.         lutil_MD5Init(&ctx);
  111.         lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, passwd->bv_len);
  112.         lutil_MD5Update(&ctx, "$apr1$", 6);
  113.         lutil_MD5Update(&ctx, (const unsigned char *) salt->bv_val, salt->bv_len);
  114.         /* Inner hash */
  115.         lutil_MD5Init(&ctx1);
  116.         lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len);
  117.         lutil_MD5Update(&ctx1, (const unsigned char *) salt->bv_val, salt->bv_len);
  118.         lutil_MD5Update(&ctx1, (const unsigned char *) passwd->bv_val, passwd->bv_len);
  119.         lutil_MD5Final(digest, &ctx1);
  120.         /* Nom start mixing things up */
  121.         for (n = passwd->bv_len; n > 0; n -= LUTIL_MD5_BYTES)
  122.                 lutil_MD5Update(&ctx, digest,
  123.                                 (n > LUTIL_MD5_BYTES ? LUTIL_MD5_BYTES : n));
  124.         memset(digest, 0, LUTIL_MD5_BYTES);
  125.         /* Curiouser and curiouser... */
  126.         for (n = passwd->bv_len; n; n >>= 1)
  127.                 if (n & 1)
  128.                         lutil_MD5Update(&ctx, digest, 1);
  129.                 else
  130.                         lutil_MD5Update(&ctx, (const unsigned char *) passwd->bv_val, 1);
  131.         lutil_MD5Final(digest, &ctx);
  132.         /*
  133.          * Repeatedly hash things into the final value. This was originally
  134.          * intended to slow the algorithm down.
  135.          */
  136.         for (n = 0; n < 1000; n++) {
  137.                 lutil_MD5Init(&ctx1);
  138.                 if (n & 1)
  139.                         lutil_MD5Update(&ctx1,
  140.                                 (const unsigned char *) passwd->bv_val, passwd->bv_len);
  141.                 else
  142.                         lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES);
  143.  
  144.                 if (n % 3)
  145.                         lutil_MD5Update(&ctx1,
  146.                                 (const unsigned char *) salt->bv_val, salt->bv_len);
  147.                 if (n % 7)
  148.                         lutil_MD5Update(&ctx1,
  149.                                 (const unsigned char *) passwd->bv_val, passwd->bv_len);
  150.  
  151.                 if (n & 1)
  152.                         lutil_MD5Update(&ctx1, digest, LUTIL_MD5_BYTES);
  153.                 else
  154.                         lutil_MD5Update(&ctx1,
  155.                                 (const unsigned char *) passwd->bv_val, passwd->bv_len);
  156.                 lutil_MD5Final(digest, &ctx1);
  157.         }
  158. }
  159.  
  160. static int chk_apr1(
  161.         const struct berval *scheme,
  162.         const struct berval *passwd,
  163.         const struct berval *cred,
  164.         const char **text)
  165. {
  166.         unsigned char digest[LUTIL_MD5_BYTES];
  167.         unsigned char *orig_pass;
  168.         int rc, n;
  169.         struct berval salt;
  170.  
  171.         /* safety check */
  172.         n = LUTIL_BASE64_DECODE_LEN(passwd->bv_len);
  173.         if (n <= sizeof(digest))
  174.                 return LUTIL_PASSWD_ERR;
  175.  
  176.         /* base64 un-encode password hash */
  177.         orig_pass = (unsigned char *) ber_memalloc((size_t) (n + 1));
  178.  
  179.         if (orig_pass == NULL)
  180.                 return LUTIL_PASSWD_ERR;
  181.  
  182.         rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
  183.  
  184.         if (rc <= (int) sizeof(digest)) {
  185.                 ber_memfree(orig_pass);
  186.                 return LUTIL_PASSWD_ERR;
  187.         }
  188.  
  189.         salt.bv_val = (char *) &orig_pass[sizeof(digest)];
  190.         salt.bv_len = rc - sizeof(digest);
  191.  
  192.         /* the only difference between this and straight PHK is the magic */
  193.         do_apr_hash(cred, &salt, digest);
  194.  
  195.         if (text)
  196.                 *text = NULL;
  197.  
  198.         /* compare */
  199.         rc = memcmp((char *) orig_pass, (char *) digest, sizeof(digest));
  200.         ber_memfree(orig_pass);
  201.         return rc ?  LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK;
  202. }
  203.  
  204. static int hash_apr1(
  205.         const struct berval *scheme,
  206.         const struct berval *passwd,
  207.         struct berval *hash,
  208.         const char **text)
  209. {
  210.         unsigned char digest_buf[LUTIL_MD5_BYTES];
  211.         char salt_buf[APR_SALT_SIZE];
  212.         struct berval digest;
  213.         struct berval salt;
  214.         int n;
  215.  
  216.         digest.bv_val = (char *) digest_buf;
  217.         digest.bv_len = sizeof(digest_buf);
  218.         salt.bv_val = salt_buf;
  219.         salt.bv_len = APR_SALT_SIZE;
  220.  
  221.         /* generate random salt */
  222.         if (lutil_entropy( (unsigned char *) salt.bv_val, salt.bv_len) < 0)
  223.                 return LUTIL_PASSWD_ERR;
  224.         /* limit it to characters in the 64-char set */
  225.         for (n = 0; n < salt.bv_len; n++)
  226.                 salt.bv_val[n] = apr64[salt.bv_val[n] % (sizeof(apr64) - 1)];
  227.  
  228.         /* the only difference between this and straight PHK is the magic */
  229.         do_apr_hash(passwd, &salt, digest_buf);
  230.  
  231.         if (text)
  232.                 *text = NULL;
  233.  
  234.         return pw_string64(scheme, &digest, hash, &salt);
  235. }
  236.  
  237. int init_module(int argc, char *argv[]) {
  238.         return lutil_passwd_add((struct berval *) &scheme, chk_apr1, hash_apr1);
  239. }