123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include <kopano/platform.h>
- #include "plugin.h"
- #include <openssl/des.h>
- #include <openssl/md5.h>
- #include <openssl/sha.h>
- #include <cstring>
- #include <iostream>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <kopano/stringutil.h>
- #include "ldappasswords.h"
- using namespace std;
- namespace KC {
- static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- /**
- * Encode string in base-64
- *
- * @param[out] out the buffer to which the result will be written.
- * @param[in] in the input string, not necessarily 0-terminated.
- * @param[in] len the number of bytes from \c in to encode.
- *
- * The buffer \c out must be large enough to hold the result, which is
- * \c len / 3 * 4 + 4 (approximately).
- */
- static void b64_encode(char *out, const unsigned char *in, unsigned int len) {
- unsigned int i, j;
- unsigned char bytes[3];
- for (i = j = 0; i < len / 3 * 3 + 3; i += 3) {
- bytes[0] = in[i];
- out[j++] = b64chars[(bytes[0] >> 2) & 0x3f];
- if (i + 1 >= len)
- bytes[1] = 0;
- else
- bytes[1] = in[i + 1];
- out[j++] = b64chars[((bytes[0] << 4) & 0x30) | ((bytes[1] >> 4) & 0x0f)];
- if (i + 2 >= len)
- bytes[2] = 0;
- else
- bytes[2] = in[i + 2];
- if (i + 1 < len)
- out[j++] = b64chars[((bytes[1] << 2) & 0x3c) | ((bytes[2] >> 6) & 0x03)];
- else
- out[j++] = '=';
- if (i + 2 < len)
- out[j++] = b64chars[bytes[2] & 0x3f];
- else
- out[j++] = '=';
- }
- out[j++] = 0;
- }
- static char *password_encrypt_crypt(const char *data, unsigned int len) {
- char salt[3];
- rand_get(salt, 2);
- salt[2] = '\0';
- char cryptbuf[32];
- DES_fcrypt(data, salt, cryptbuf);
- auto res = new char[32];
- snprintf(res, 32, "{CRYPT}%s", cryptbuf);
- return res;
- }
- static int password_check_crypt(const char *data, unsigned int len, const char *crypted) {
- char salt[3];
- char cryptbuf[32];
- salt[0] = crypted[0];
- salt[1] = crypted[1];
- salt[2] = 0;
- DES_fcrypt(data, salt, cryptbuf);
- if (!strcmp(cryptbuf, crypted))
- return 0;
- else
- return 1;
- }
- static char *password_encrypt_md5(const char *data, unsigned int len) {
- unsigned char md5_out[MD5_DIGEST_LENGTH];
- const int base64_len = MD5_DIGEST_LENGTH * 4 / 3 + 4;
- char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
- char *res;
- MD5((unsigned char *) data, len, md5_out);
- b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH);
- res = new char[base64_len + 12];
- snprintf(res, base64_len + 11, "{MD5}%s", b64_out);
- return res;
- }
- static int password_check_md5(const char *data, unsigned int len, const char *crypted) {
- unsigned char md5_out[MD5_DIGEST_LENGTH];
- char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
- MD5((unsigned char *) data, len, md5_out);
- b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH);
- if (!strcmp(b64_out, crypted))
- return 0;
- else
- return 1;
- }
- // md5sum + salt at the end. md5sum length == 16, salt length == 4
- static char *password_encrypt_smd5(const char *data, unsigned int len) {
- MD5_CTX ctx;
- unsigned char md5_out[MD5_DIGEST_LENGTH + 4];
- unsigned char *salt = md5_out + MD5_DIGEST_LENGTH; // salt is at the end of the digest
- const int base64_len = MD5_DIGEST_LENGTH * 4 / 3 + 4;
- char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
- char *res;
- rand_get(reinterpret_cast<char *>(salt), 4);
- MD5_Init(&ctx);
- MD5_Update(&ctx, data, len);
- MD5_Update(&ctx, salt, 4);
- MD5_Final(md5_out, &ctx); // writes upto the salt
- b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH + 4);
- res = new char[base64_len + 12];
- snprintf(res, base64_len + 11, "{SMD5}%s", b64_out);
- return res;
- }
- static int password_check_smd5(const char *data, unsigned int len, const char *crypted) {
- std::string digest;
- std::string salt;
- unsigned char md5_out[MD5_DIGEST_LENGTH];
- char b64_out[MD5_DIGEST_LENGTH * 4 / 3 + 4];
- MD5_CTX ctx;
- digest = base64_decode(crypted);
- salt.assign(digest.c_str()+MD5_DIGEST_LENGTH, digest.length()-MD5_DIGEST_LENGTH);
- MD5_Init(&ctx);
- MD5_Update(&ctx, data, len);
- MD5_Update(&ctx, salt.c_str(), salt.length());
- MD5_Final(md5_out, &ctx);
- b64_encode(b64_out, md5_out, MD5_DIGEST_LENGTH);
- if (!strncmp(b64_out, crypted, MD5_DIGEST_LENGTH))
- return 0;
- else
- return 1;
- }
- static char *password_encrypt_ssha(const char *data, unsigned int len, bool bSalted) {
- unsigned char SHA_out[SHA_DIGEST_LENGTH];
- const int base64_len = SHA_DIGEST_LENGTH * 4 / 3 + 4;
- char b64_out[SHA_DIGEST_LENGTH * 4 / 3 + 4];
- char *res;
- unsigned char salt[4];
- std::string pwd;
- pwd.assign(data, len);
- if (bSalted) {
- rand_get(reinterpret_cast<char *>(salt), sizeof(salt));
- pwd.append(reinterpret_cast<const char *>(salt), sizeof(salt));
- }
- SHA1((const unsigned char*)pwd.c_str(), pwd.length(), SHA_out);
- b64_encode(b64_out, SHA_out, SHA_DIGEST_LENGTH);
- res = new char[base64_len + 12];
- snprintf(res, base64_len + 11, "{%s}%s", bSalted ? "SSHA" : "SHA", b64_out);
- return res;
- }
- static int password_check_ssha(const char *data, unsigned int len, const char *crypted, bool bSalted) {
- std::string digest;
- std::string salt;
- std::string pwd;
- unsigned char SHA_out[SHA_DIGEST_LENGTH];
- pwd.assign(data, len);
- digest = base64_decode(crypted);
- if (bSalted) {
- salt.assign(digest.c_str()+SHA_DIGEST_LENGTH, digest.length()-SHA_DIGEST_LENGTH);
- pwd += salt;
- }
- memset(SHA_out, 0, sizeof(SHA_out));
- SHA1((const unsigned char*)pwd.c_str(), pwd.length(), SHA_out);
- digest.assign((char*)SHA_out, SHA_DIGEST_LENGTH);
- if (bSalted)
- digest += salt;
- pwd = base64_encode((const unsigned char*)digest.c_str(), digest.length());
- if (!strcmp(pwd.c_str(), crypted))
- return 0;
- else
- return 1;
- }
- char *encryptPassword(int type, const char *password) {
- switch(type) {
- case PASSWORD_CRYPT:
- return password_encrypt_crypt(password, strlen(password));
- case PASSWORD_MD5:
- return password_encrypt_md5(password, strlen(password));
- case PASSWORD_SMD5:
- return password_encrypt_smd5(password, strlen(password));
- case PASSWORD_SHA:
- return password_encrypt_ssha(password, strlen(password), false);
- case PASSWORD_SSHA:
- return password_encrypt_ssha(password, strlen(password), true);
- default:
- return NULL;
- }
- }
- int checkPassword(int type, const char *password, const char *crypted) {
- switch(type) {
- case PASSWORD_CRYPT:
- return password_check_crypt(password, strlen(password), crypted);
- case PASSWORD_MD5:
- return password_check_md5(password, strlen(password), crypted);
- case PASSWORD_SMD5:
- return password_check_smd5(password, strlen(password), crypted);
- case PASSWORD_SHA:
- return password_check_ssha(password, strlen(password), crypted, false);
- case PASSWORD_SSHA:
- return password_check_ssha(password, strlen(password), crypted, true);
- default:
- return 1;
- }
- }
- } /* namespace */
|