smd5_pwd.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2005 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. /*
  41. * Based on MD5 Password Encryption/Comparison routines by David Irving,
  42. * Fred Brittain, and Aaron Gagnon -- University of Maine Farmington
  43. * Donated to the RedHat Directory Server Project 2005-06-10
  44. */
  45. #include <string.h>
  46. #include <sys/types.h>
  47. #include <stdio.h>
  48. #include <pk11func.h>
  49. #include <nss.h>
  50. #include <nssb64.h>
  51. #include <sechash.h>
  52. #include "pwdstorage.h"
  53. #define MD5_DEFAULT_SALT_LENGTH 4
  54. #define MD5_MAX_SALT_LENGTH 16
  55. #define SALTED_MD5_SUBSYSTEM_NAME "Salted MD5 password hash"
  56. int
  57. smd5_pw_cmp( const char *userpwd, const char *dbpwd )
  58. {
  59. int rc=-1;
  60. PK11Context *ctx=NULL;
  61. unsigned int outLen;
  62. unsigned char userhash[MD5_LENGTH];
  63. int hash_len;
  64. char quick_dbhash[MD5_LENGTH + MD5_DEFAULT_SALT_LENGTH + 1];
  65. char *dbhash = quick_dbhash;
  66. struct berval salt;
  67. char *hashresult = NULL;
  68. ctx = PK11_CreateDigestContext(SEC_OID_MD5);
  69. if (ctx == NULL) {
  70. slapi_log_error(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  71. "Could not create context for digest operation for password compare");
  72. goto loser;
  73. }
  74. /*
  75. * Decode hash stored in database.
  76. */
  77. hash_len = pwdstorage_base64_decode_len(dbpwd, 0);
  78. if ( hash_len >= sizeof(quick_dbhash) ) { /* get more space: */
  79. dbhash = (char*) slapi_ch_calloc( hash_len + 1, sizeof(char) );
  80. if ( dbhash == NULL ) goto loser;
  81. } else {
  82. memset( quick_dbhash, 0, sizeof(quick_dbhash) );
  83. }
  84. hashresult = PL_Base64Decode( dbpwd, 0, dbhash );
  85. if (NULL == hashresult) {
  86. slapi_log_error( SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  87. "smd5_pw_cmp: userPassword \"%s\" is the wrong length "
  88. "or is not properly encoded BASE64\n", dbpwd );
  89. goto loser;
  90. }
  91. salt.bv_val = (void*)(dbhash + MD5_LENGTH); /* salt starts after hash value */
  92. salt.bv_len = hash_len - MD5_LENGTH; /* remaining bytes must be salt */
  93. /* create the hash */
  94. memset( userhash, 0, sizeof(userhash) );
  95. PK11_DigestBegin(ctx);
  96. PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
  97. PK11_DigestOp(ctx, (unsigned char*)(salt.bv_val), salt.bv_len);
  98. PK11_DigestFinal(ctx, userhash, &outLen, sizeof userhash);
  99. PK11_DestroyContext(ctx, 1);
  100. /* Compare everything up to the salt. */
  101. rc = memcmp( userhash, dbhash, MD5_LENGTH );
  102. loser:
  103. if ( dbhash && dbhash != quick_dbhash ) slapi_ch_free_string( (char **)&dbhash );
  104. return rc;
  105. }
  106. char *
  107. smd5_pw_enc( const char *pwd )
  108. {
  109. char * bver, *enc=NULL;
  110. PK11Context *ctx=NULL;
  111. unsigned int outLen;
  112. unsigned char hash_out[MD5_LENGTH + MD5_DEFAULT_SALT_LENGTH];
  113. unsigned char b2a_out[(MD5_LENGTH*2) + (MD5_MAX_SALT_LENGTH*2)]; /* conservative */
  114. unsigned char *salt = hash_out + MD5_LENGTH;
  115. struct berval saltval;
  116. SECItem binary_item;
  117. ctx = PK11_CreateDigestContext(SEC_OID_MD5);
  118. if (ctx == NULL) {
  119. slapi_log_error(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  120. "Could not create context for digest operation for password encoding");
  121. return NULL;
  122. }
  123. /* prepare the hash output area */
  124. memset( hash_out, 0, sizeof(hash_out) );
  125. /* generate a new random salt */
  126. slapi_rand_array( (void *)salt, MD5_DEFAULT_SALT_LENGTH );
  127. saltval.bv_val = (void*)salt;
  128. saltval.bv_len = MD5_DEFAULT_SALT_LENGTH;
  129. /* create the hash */
  130. PK11_DigestBegin(ctx);
  131. PK11_DigestOp(ctx, (const unsigned char *)pwd, strlen(pwd));
  132. PK11_DigestOp(ctx, (unsigned char*)(saltval.bv_val), saltval.bv_len);
  133. PK11_DigestFinal(ctx, hash_out, &outLen, sizeof hash_out);
  134. PK11_DestroyContext(ctx, 1);
  135. /* convert the binary hash to base64 */
  136. binary_item.data = hash_out;
  137. binary_item.len = outLen + MD5_DEFAULT_SALT_LENGTH;
  138. bver = NSSBase64_EncodeItem(NULL, (char *)b2a_out, sizeof b2a_out, &binary_item);
  139. if (bver) {
  140. enc = slapi_ch_smprintf("%c%s%c%s", PWD_HASH_PREFIX_START, SALTED_MD5_SCHEME_NAME,
  141. PWD_HASH_PREFIX_END, bver );
  142. } else {
  143. slapi_log_error(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  144. "Could not base64 encode hashed value for password encoding");
  145. }
  146. return( enc );
  147. }