Advertisement
Guest User

apr1.c

a guest
Feb 6th, 2011
375
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.83 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement