summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libsylph/account.c49
-rw-r--r--libsylph/prefs_common.c2
-rw-r--r--libsylph/prefs_common.h1
-rw-r--r--libsylph/ssl.c96
-rw-r--r--libsylph/ssl.h24
5 files changed, 161 insertions, 11 deletions
diff --git a/libsylph/account.c b/libsylph/account.c
index 95d19fc..e4cb5cc 100644
--- a/libsylph/account.c
+++ b/libsylph/account.c
@@ -37,6 +37,8 @@
37#include "utils.h" 37#include "utils.h"
38#include "sylmain.h" 38#include "sylmain.h"
39#include "prefs_common.h" 39#include "prefs_common.h"
40#include "ssl.h"
41
40 42
41PrefsAccount *cur_account; 43PrefsAccount *cur_account;
42 44
@@ -53,9 +55,52 @@ void account_read_config_all(void)
53 gchar buf[PREFSBUFSIZE]; 55 gchar buf[PREFSBUFSIZE];
54 PrefsAccount *ac_prefs; 56 PrefsAccount *ac_prefs;
55#if USE_SSL 57#if USE_SSL
56 gchar *master_password; 58 guint cnt;
59 gchar *master_password, *master_password_confirm;
57 if (prefs_common.use_master_password) { 60 if (prefs_common.use_master_password) {
58 master_password = input_query_password("Sylpheed", "Master password"); 61 if (prefs_common.master_password_hash != NULL) {
62 for (cnt = 0; cnt < 3; ++cnt) {
63 /* allow 3 attempts to enter the master password */
64 master_password = input_query_password(_("Sylpheed"),
65 _("Master password"));
66 if (check_password(
67 master_password,
68 prefs_common.master_password_hash) == RC_OK) {
69 break;
70 }
71 debug_print(_("Wrong master password entered (%d)\n"), cnt);
72 g_free(master_password);
73 master_password = NULL;
74 }
75 } else {
76 /* No master password set (no master_password_hash) */
77 for (cnt = 0; cnt < 3; ++cnt) {
78 master_password = input_query_password(_("Sylpheed"),
79 _("Master password"));
80 master_password_confirm = input_query_password(
81 _("Sylpheed"),
82 _("Master password confirmation"));
83 if (strcmp(master_password, master_password_confirm) == 0) {
84 /* The passwords match */
85 g_free(master_password_confirm);
86 if (generate_password_hash(
87 &prefs_common.master_password_hash,
88 master_password,
89 NULL) != RC_OK) {
90 debug_print(
91 _("Could not generate master password hash"));
92 g_free(master_password);
93 continue;
94 }
95 prefs_common_write_config();
96 break;
97 }
98 g_free(master_password);
99 g_free(master_password_confirm);
100 master_password = NULL;
101 }
102 }
103 /* TODO: Warning if password is NULL */
59 } else { 104 } else {
60 master_password = NULL; 105 master_password = NULL;
61 } 106 }
diff --git a/libsylph/prefs_common.c b/libsylph/prefs_common.c
index 1f1d3e2..6c20319 100644
--- a/libsylph/prefs_common.c
+++ b/libsylph/prefs_common.c
@@ -421,6 +421,8 @@ static PrefParam param[] = {
421 /* Master password */ 421 /* Master password */
422 {"use_master_password", "FALSE", &prefs_common.use_master_password, 422 {"use_master_password", "FALSE", &prefs_common.use_master_password,
423 P_BOOL}, 423 P_BOOL},
424 {"master_password_hash", NULL, &prefs_common.master_password_hash,
425 P_STRING},
424 426
425 /* Interface */ 427 /* Interface */
426 {"separate_folder", "FALSE", &prefs_common.sep_folder, P_BOOL}, 428 {"separate_folder", "FALSE", &prefs_common.sep_folder, P_BOOL},
diff --git a/libsylph/prefs_common.h b/libsylph/prefs_common.h
index ef5bb9b..bc1d2f3 100644
--- a/libsylph/prefs_common.h
+++ b/libsylph/prefs_common.h
@@ -251,6 +251,7 @@ struct _PrefsCommon
251 251
252 /* Master password */ 252 /* Master password */
253 gboolean use_master_password; 253 gboolean use_master_password;
254 gchar *master_password_hash;
254 255
255 /* Interface */ 256 /* Interface */
256 gboolean sep_folder; 257 gboolean sep_folder;
diff --git a/libsylph/ssl.c b/libsylph/ssl.c
index 82b77b4..5042f74 100644
--- a/libsylph/ssl.c
+++ b/libsylph/ssl.c
@@ -36,6 +36,8 @@
36#define CIPHER EVP_aes_256_cfb() 36#define CIPHER EVP_aes_256_cfb()
37#define KEY_HASH EVP_sha256() 37#define KEY_HASH EVP_sha256()
38#define DIGEST_HASH EVP_sha256() 38#define DIGEST_HASH EVP_sha256()
39#define PBKDF2_DIGEST_SIZE 64
40#define PBKDF2_ITERATIONS 100000
39 41
40static SSL_CTX *ssl_ctx_SSLv23 = NULL; 42static SSL_CTX *ssl_ctx_SSLv23 = NULL;
41static SSL_CTX *ssl_ctx_TLSv1 = NULL; 43static SSL_CTX *ssl_ctx_TLSv1 = NULL;
@@ -779,4 +781,98 @@ cleanup:
779 781
780} 782}
781 783
784gint generate_password_hash(gchar **password_hash,
785 const gchar *password,
786 const guchar *salt) {
787 /*
788 * Hashes 'password' using PKCS5_PBKDF2_HMAC with SHA512 and 'salt',
789 * and assigns a string to 'password_hash' with the following format:
790 * pbkdf2_sha512$iterations$base64(salt)$base64(password_hash)
791 */
792 guchar lsalt[SALT_SIZE];
793 gchar *PBKDF2_digest, *salt_b64, *digest_b64;
794
795 if (salt == NULL) {
796 if (RAND_bytes(lsalt, SALT_SIZE) != 1) {
797 debug_print("Random problems...\n");
798 return RC_ERROR;
799 }
800 } else {
801 memcpy(lsalt, salt, SALT_SIZE);
802 }
803
804 PBKDF2_digest = OPENSSL_malloc(PBKDF2_DIGEST_SIZE);
805 OPENSSL_cleanse(PBKDF2_digest, PBKDF2_DIGEST_SIZE);
806
807 PKCS5_PBKDF2_HMAC(password,
808 strlen(password),
809 lsalt,
810 SALT_SIZE,
811 PBKDF2_ITERATIONS,
812 EVP_sha512(),
813 PBKDF2_DIGEST_SIZE,
814 (guchar *) PBKDF2_digest);
815 digest_b64 = g_base64_encode((guchar *) PBKDF2_digest, PBKDF2_DIGEST_SIZE);
816 OPENSSL_cleanse(PBKDF2_digest, PBKDF2_DIGEST_SIZE);
817 OPENSSL_free(PBKDF2_digest);
818
819 salt_b64 = g_base64_encode(lsalt, SALT_SIZE);
820
821 *password_hash = g_strdup_printf("pbkdf2_sha512$%d$%s$%s",
822 PBKDF2_ITERATIONS,
823 salt_b64,
824 digest_b64);
825
826 OPENSSL_cleanse(digest_b64, strlen(digest_b64));
827 OPENSSL_free(digest_b64);
828
829 OPENSSL_cleanse(salt_b64, strlen(salt_b64));
830 OPENSSL_free(salt_b64);
831
832 return RC_OK;
833
834}
835
836gint check_password(const gchar *password, const gchar *password_hash) {
837
838 gint token_counter, rc;
839 guchar *salt;
840 gchar **tokens, *new_hash;
841 gsize salt_length;
842
843 rc = RC_ERROR;
844 tokens = g_strsplit(password_hash,
845 "$",
846 -1);
847 token_counter = 0;
848 while (*(tokens + token_counter) != NULL) {
849 ++token_counter;
850 }
851
852 if (token_counter != 4) {
853 debug_print("Invalid password hash...\n");
854 goto cleanup;
855 }
856
857 salt = g_base64_decode(*(tokens + 2), &salt_length);
858 if (salt_length != SALT_SIZE) {
859 debug_print("Salt size does not match\n");
860 goto cleanup;
861 }
862
863 if (generate_password_hash(&new_hash, password, salt) != RC_OK) {
864 debug_print("Password hash generation failed\n");
865 goto cleanup;
866 }
867
868 rc = g_strcmp0(password_hash, new_hash);
869
870cleanup:
871 g_free(salt);
872 g_free(new_hash);
873 g_strfreev(tokens);
874 return rc;
875
876}
877
782#endif /* USE_SSL */ 878#endif /* USE_SSL */
diff --git a/libsylph/ssl.h b/libsylph/ssl.h
index 94ab4b7..6338911 100644
--- a/libsylph/ssl.h
+++ b/libsylph/ssl.h
@@ -68,17 +68,23 @@ void ssl_set_verify_func (SSLVerifyFunc func);
68 68
69/* master password related code */ 69/* master password related code */
70gint encrypt_data(gchar **encrypted, 70gint encrypt_data(gchar **encrypted,
71 gint *length_encrypted, 71 gint *length_encrypted,
72 const gchar *data, 72 const gchar *data,
73 const gchar *passphrase, 73 const gchar *passphrase,
74 gint length_data, 74 gint length_data,
75 guint min_data_length, 75 guint min_data_length,
76 gboolean rnd_salt); 76 gboolean rnd_salt);
77 77
78gint decrypt_data(gchar **decrypted, 78gint decrypt_data(gchar **decrypted,
79 const gchar *data, 79 const gchar *data,
80 const gchar *passphrase, 80 const gchar *passphrase,
81 gint length_data); 81 gint length_data);
82
83gint generate_password_hash(gchar **password_hash,
84 const gchar *password,
85 const guchar *salt);
86
87gint check_password(const gchar *password, const gchar *password_hash);
82/* ---------------------------- */ 88/* ---------------------------- */
83#endif /* USE_SSL */ 89#endif /* USE_SSL */
84 90