1
0

smd5_pwd.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2005 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK **/
  8. #ifdef HAVE_CONFIG_H
  9. # include <config.h>
  10. #endif
  11. /*
  12. * Based on MD5 Password Encryption/Comparison routines by David Irving,
  13. * Fred Brittain, and Aaron Gagnon -- University of Maine Farmington
  14. * Donated to the RedHat Directory Server Project 2005-06-10
  15. */
  16. #include <string.h>
  17. #include <sys/types.h>
  18. #include <stdio.h>
  19. #include <pk11func.h>
  20. #include <nss.h>
  21. #include <nssb64.h>
  22. #include <sechash.h>
  23. #include "pwdstorage.h"
  24. #define MD5_DEFAULT_SALT_LENGTH 4
  25. #define MD5_MAX_SALT_LENGTH 16
  26. #define SALTED_MD5_SUBSYSTEM_NAME "Salted MD5 password hash"
  27. int
  28. smd5_pw_cmp( const char *userpwd, const char *dbpwd )
  29. {
  30. int rc=-1;
  31. PK11Context *ctx=NULL;
  32. unsigned int outLen;
  33. unsigned char userhash[MD5_LENGTH];
  34. int hash_len;
  35. char quick_dbhash[MD5_LENGTH + MD5_DEFAULT_SALT_LENGTH + 1];
  36. char *dbhash = quick_dbhash;
  37. struct berval salt;
  38. char *hashresult = NULL;
  39. ctx = PK11_CreateDigestContext(SEC_OID_MD5);
  40. if (ctx == NULL) {
  41. slapi_log_error(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  42. "Could not create context for digest operation for password compare");
  43. goto loser;
  44. }
  45. /*
  46. * Decode hash stored in database.
  47. */
  48. hash_len = pwdstorage_base64_decode_len(dbpwd, 0);
  49. if ( hash_len >= sizeof(quick_dbhash) ) { /* get more space: */
  50. dbhash = (char*) slapi_ch_calloc( hash_len + 1, sizeof(char) );
  51. if ( dbhash == NULL ) goto loser;
  52. } else {
  53. memset( quick_dbhash, 0, sizeof(quick_dbhash) );
  54. }
  55. hashresult = PL_Base64Decode( dbpwd, 0, dbhash );
  56. if (NULL == hashresult) {
  57. slapi_log_error( SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  58. "smd5_pw_cmp: userPassword \"%s\" is the wrong length "
  59. "or is not properly encoded BASE64\n", dbpwd );
  60. goto loser;
  61. }
  62. salt.bv_val = (void*)(dbhash + MD5_LENGTH); /* salt starts after hash value */
  63. salt.bv_len = hash_len - MD5_LENGTH; /* remaining bytes must be salt */
  64. /* create the hash */
  65. memset( userhash, 0, sizeof(userhash) );
  66. PK11_DigestBegin(ctx);
  67. PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
  68. PK11_DigestOp(ctx, (unsigned char*)(salt.bv_val), salt.bv_len);
  69. PK11_DigestFinal(ctx, userhash, &outLen, sizeof userhash);
  70. PK11_DestroyContext(ctx, 1);
  71. /* Compare everything up to the salt. */
  72. rc = memcmp( userhash, dbhash, MD5_LENGTH );
  73. loser:
  74. if ( dbhash && dbhash != quick_dbhash ) slapi_ch_free_string( (char **)&dbhash );
  75. return rc;
  76. }
  77. char *
  78. smd5_pw_enc( const char *pwd )
  79. {
  80. char * bver, *enc=NULL;
  81. PK11Context *ctx=NULL;
  82. unsigned int outLen;
  83. unsigned char hash_out[MD5_LENGTH + MD5_DEFAULT_SALT_LENGTH];
  84. unsigned char b2a_out[(MD5_LENGTH*2) + (MD5_MAX_SALT_LENGTH*2)]; /* conservative */
  85. unsigned char *salt = hash_out + MD5_LENGTH;
  86. struct berval saltval;
  87. SECItem binary_item;
  88. ctx = PK11_CreateDigestContext(SEC_OID_MD5);
  89. if (ctx == NULL) {
  90. slapi_log_error(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  91. "Could not create context for digest operation for password encoding");
  92. return NULL;
  93. }
  94. /* prepare the hash output area */
  95. memset( hash_out, 0, sizeof(hash_out) );
  96. /* generate a new random salt */
  97. slapi_rand_array( (void *)salt, MD5_DEFAULT_SALT_LENGTH );
  98. saltval.bv_val = (void*)salt;
  99. saltval.bv_len = MD5_DEFAULT_SALT_LENGTH;
  100. /* create the hash */
  101. PK11_DigestBegin(ctx);
  102. PK11_DigestOp(ctx, (const unsigned char *)pwd, strlen(pwd));
  103. PK11_DigestOp(ctx, (unsigned char*)(saltval.bv_val), saltval.bv_len);
  104. PK11_DigestFinal(ctx, hash_out, &outLen, sizeof hash_out);
  105. PK11_DestroyContext(ctx, 1);
  106. /* convert the binary hash to base64 */
  107. binary_item.data = hash_out;
  108. binary_item.len = outLen + MD5_DEFAULT_SALT_LENGTH;
  109. bver = NSSBase64_EncodeItem(NULL, (char *)b2a_out, sizeof b2a_out, &binary_item);
  110. if (bver) {
  111. enc = slapi_ch_smprintf("%c%s%c%s", PWD_HASH_PREFIX_START, SALTED_MD5_SCHEME_NAME,
  112. PWD_HASH_PREFIX_END, bver );
  113. } else {
  114. slapi_log_error(SLAPI_LOG_PLUGIN, SALTED_MD5_SUBSYSTEM_NAME,
  115. "Could not base64 encode hashed value for password encoding");
  116. }
  117. return( enc );
  118. }