diff options
Diffstat (limited to 'libsylph')
| -rw-r--r-- | libsylph/account.c | 49 | ||||
| -rw-r--r-- | libsylph/prefs_common.c | 2 | ||||
| -rw-r--r-- | libsylph/prefs_common.h | 1 | ||||
| -rw-r--r-- | libsylph/ssl.c | 96 | ||||
| -rw-r--r-- | libsylph/ssl.h | 24 |
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 | ||
| 41 | PrefsAccount *cur_account; | 43 | PrefsAccount *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 | ||
| 40 | static SSL_CTX *ssl_ctx_SSLv23 = NULL; | 42 | static SSL_CTX *ssl_ctx_SSLv23 = NULL; |
| 41 | static SSL_CTX *ssl_ctx_TLSv1 = NULL; | 43 | static SSL_CTX *ssl_ctx_TLSv1 = NULL; |
| @@ -779,4 +781,98 @@ cleanup: | |||
| 779 | 781 | ||
| 780 | } | 782 | } |
| 781 | 783 | ||
| 784 | gint 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 | |||
| 836 | gint 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 | |||
| 870 | cleanup: | ||
| 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 */ |
| 70 | gint encrypt_data(gchar **encrypted, | 70 | gint 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 | ||
| 78 | gint decrypt_data(gchar **decrypted, | 78 | gint 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 | |||
| 83 | gint generate_password_hash(gchar **password_hash, | ||
| 84 | const gchar *password, | ||
| 85 | const guchar *salt); | ||
| 86 | |||
| 87 | gint check_password(const gchar *password, const gchar *password_hash); | ||
| 82 | /* ---------------------------- */ | 88 | /* ---------------------------- */ |
| 83 | #endif /* USE_SSL */ | 89 | #endif /* USE_SSL */ |
| 84 | 90 | ||
