ldappasswords.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include "plugin.h"
  19. #include <openssl/des.h>
  20. #include <openssl/md5.h>
  21. #include <openssl/sha.h>
  22. #include <cstring>
  23. #include <iostream>
  24. #include <fcntl.h>
  25. #include <sys/stat.h>
  26. #include <sys/types.h>
  27. #include <kopano/stringutil.h>
  28. #include "ldappasswords.h"
  29. using namespace std;
  30. namespace KC {
  31. static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  32. /**
  33. * Encode string in base-64
  34. *
  35. * @param[out] out the buffer to which the result will be written.
  36. * @param[in] in the input string, not necessarily 0-terminated.
  37. * @param[in] len the number of bytes from \c in to encode.
  38. *
  39. * The buffer \c out must be large enough to hold the result, which is
  40. * \c len / 3 * 4 + 4 (approximately).
  41. */
  42. static void b64_encode(char *out, const unsigned char *in, unsigned int len) {
  43. unsigned int i, j;
  44. unsigned char bytes[3];
  45. for (i = j = 0; i < len / 3 * 3 + 3; i += 3) {
  46. bytes[0] = in[i];
  47. out[j++] = b64chars[(bytes[0] >> 2) & 0x3f];
  48. if (i + 1 >= len)
  49. bytes[1] = 0;
  50. else
  51. bytes[1] = in[i + 1];
  52. out[j++] = b64chars[((bytes[0] << 4) & 0x30) | ((bytes[1] >> 4) & 0x0f)];
  53. if (i + 2 >= len)
  54. bytes[2] = 0;
  55. else
  56. bytes[2] = in[i + 2];
  57. if (i + 1 < len)
  58. out[j++] = b64chars[((bytes[1] << 2) & 0x3c) | ((bytes[2] >> 6) & 0x03)];
  59. else
  60. out[j++] = '=';
  61. if (i + 2 < len)
  62. out[j++] = b64chars[bytes[2] & 0x3f];
  63. else
  64. out[j++] = '=';
  65. }
  66. out[j++] = 0;
  67. }
  68. static char *password_encrypt_crypt(const char *data, unsigned int len) {
  69. char salt[3];
  70. rand_get(salt, 2);
  71. salt[2] = '\0';
  72. char cryptbuf[32];
  73. DES_fcrypt(data, salt, cryptbuf);
  74. auto res = new char[32];
  75. snprintf(res, 32, "{CRYPT}%s", cryptbuf);
  76. return res;
  77. }
  78. static int password_check_crypt(const char *data, unsigned int len, const char *crypted) {
  79. char salt[3];
  80. char cryptbuf[32];
  81. salt[0] = crypted[0];
  82. salt[1] = crypted[1];
  83. salt[2] = 0;
  84. DES_fcrypt(data, salt, cryptbuf);
  85. if (!strcmp(cryptbuf, crypted))
  86. return 0;
  87. else
  88. return 1;
  89. }
  90. static char *password_encrypt_md5(const char *data, unsigned int len) {
  91. unsigned char md5_out[MD5_DIGEST_LENGTH];
  92. const int base64_len = MD5_DIGEST_LENGTH * 4 / 3 + 4;
  93. char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
  94. char *res;
  95. MD5((unsigned char *) data, len, md5_out);
  96. b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH);
  97. res = new char[base64_len + 12];
  98. snprintf(res, base64_len + 11, "{MD5}%s", b64_out);
  99. return res;
  100. }
  101. static int password_check_md5(const char *data, unsigned int len, const char *crypted) {
  102. unsigned char md5_out[MD5_DIGEST_LENGTH];
  103. char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
  104. MD5((unsigned char *) data, len, md5_out);
  105. b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH);
  106. if (!strcmp(b64_out, crypted))
  107. return 0;
  108. else
  109. return 1;
  110. }
  111. // md5sum + salt at the end. md5sum length == 16, salt length == 4
  112. static char *password_encrypt_smd5(const char *data, unsigned int len) {
  113. MD5_CTX ctx;
  114. unsigned char md5_out[MD5_DIGEST_LENGTH + 4];
  115. unsigned char *salt = md5_out + MD5_DIGEST_LENGTH; // salt is at the end of the digest
  116. const int base64_len = MD5_DIGEST_LENGTH * 4 / 3 + 4;
  117. char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
  118. char *res;
  119. rand_get(reinterpret_cast<char *>(salt), 4);
  120. MD5_Init(&ctx);
  121. MD5_Update(&ctx, data, len);
  122. MD5_Update(&ctx, salt, 4);
  123. MD5_Final(md5_out, &ctx); // writes upto the salt
  124. b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH + 4);
  125. res = new char[base64_len + 12];
  126. snprintf(res, base64_len + 11, "{SMD5}%s", b64_out);
  127. return res;
  128. }
  129. static int password_check_smd5(const char *data, unsigned int len, const char *crypted) {
  130. std::string digest;
  131. std::string salt;
  132. unsigned char md5_out[MD5_DIGEST_LENGTH];
  133. char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
  134. MD5_CTX ctx;
  135. digest = base64_decode(crypted);
  136. salt.assign(digest.c_str()+MD5_DIGEST_LENGTH, digest.length()-MD5_DIGEST_LENGTH);
  137. MD5_Init(&ctx);
  138. MD5_Update(&ctx, data, len);
  139. MD5_Update(&ctx, salt.c_str(), salt.length());
  140. MD5_Final(md5_out, &ctx);
  141. b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH);
  142. if (!strncmp(b64_out, crypted, MD5_DIGEST_LENGTH))
  143. return 0;
  144. else
  145. return 1;
  146. }
  147. static char *password_encrypt_ssha(const char *data, unsigned int len, bool bSalted) {
  148. unsigned char SHA_out[SHA_DIGEST_LENGTH];
  149. const int base64_len = SHA_DIGEST_LENGTH * 4 / 3 + 4;
  150. char b64_out[SHA_DIGEST_LENGTH * 4 / 3 + 4];
  151. char *res;
  152. unsigned char salt[4];
  153. std::string pwd;
  154. pwd.assign(data, len);
  155. if (bSalted) {
  156. rand_get(reinterpret_cast<char *>(salt), sizeof(salt));
  157. pwd.append(reinterpret_cast<const char *>(salt), sizeof(salt));
  158. }
  159. SHA1((const unsigned char*)pwd.c_str(), pwd.length(), SHA_out);
  160. b64_encode(b64_out, SHA_out, SHA_DIGEST_LENGTH);
  161. res = new char[base64_len + 12];
  162. snprintf(res, base64_len + 11, "{%s}%s", bSalted ? "SSHA" : "SHA", b64_out);
  163. return res;
  164. }
  165. static int password_check_ssha(const char *data, unsigned int len, const char *crypted, bool bSalted) {
  166. std::string digest;
  167. std::string salt;
  168. std::string pwd;
  169. unsigned char SHA_out[SHA_DIGEST_LENGTH];
  170. pwd.assign(data, len);
  171. digest = base64_decode(crypted);
  172. if (bSalted) {
  173. salt.assign(digest.c_str()+SHA_DIGEST_LENGTH, digest.length()-SHA_DIGEST_LENGTH);
  174. pwd += salt;
  175. }
  176. memset(SHA_out, 0, sizeof(SHA_out));
  177. SHA1((const unsigned char*)pwd.c_str(), pwd.length(), SHA_out);
  178. digest.assign((char*)SHA_out, SHA_DIGEST_LENGTH);
  179. if (bSalted)
  180. digest += salt;
  181. pwd = base64_encode((const unsigned char*)digest.c_str(), digest.length());
  182. if (!strcmp(pwd.c_str(), crypted))
  183. return 0;
  184. else
  185. return 1;
  186. }
  187. char *encryptPassword(int type, const char *password) {
  188. switch(type) {
  189. case PASSWORD_CRYPT:
  190. return password_encrypt_crypt(password, strlen(password));
  191. case PASSWORD_MD5:
  192. return password_encrypt_md5(password, strlen(password));
  193. case PASSWORD_SMD5:
  194. return password_encrypt_smd5(password, strlen(password));
  195. case PASSWORD_SHA:
  196. return password_encrypt_ssha(password, strlen(password), false);
  197. case PASSWORD_SSHA:
  198. return password_encrypt_ssha(password, strlen(password), true);
  199. default:
  200. return NULL;
  201. }
  202. }
  203. int checkPassword(int type, const char *password, const char *crypted) {
  204. switch(type) {
  205. case PASSWORD_CRYPT:
  206. return password_check_crypt(password, strlen(password), crypted);
  207. case PASSWORD_MD5:
  208. return password_check_md5(password, strlen(password), crypted);
  209. case PASSWORD_SMD5:
  210. return password_check_smd5(password, strlen(password), crypted);
  211. case PASSWORD_SHA:
  212. return password_check_ssha(password, strlen(password), crypted, false);
  213. case PASSWORD_SSHA:
  214. return password_check_ssha(password, strlen(password), crypted, true);
  215. default:
  216. return 1;
  217. }
  218. }
  219. } /* namespace */