summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2020-03-02 00:46:10 +0100
committerSébastien Helleu <flashcode@flashtux.org>2020-03-02 00:46:10 +0100
commit2d2b49bfaa8b5585f57c45501e2f22b452123d62 (patch)
tree3afd97132915fdfa97adb3f8035d447917e0957e /src
parent1882686f8a16da7037b65c7be58cd1d00807cd9c (diff)
downloadweechat-2d2b49bfaa8b5585f57c45501e2f22b452123d62.zip
relay: accept hash of password in init command with option "password_hash"
Allowed algorithms are: * PBKDF2 (SHA256 or SHA512, salt, iterations) * SHA256 * SHA512
Diffstat (limited to 'src')
-rw-r--r--src/plugins/relay/weechat/relay-weechat-protocol.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/plugins/relay/weechat/relay-weechat-protocol.c b/src/plugins/relay/weechat/relay-weechat-protocol.c
index 1d7452a8d..0c897a6d3 100644
--- a/src/plugins/relay/weechat/relay-weechat-protocol.c
+++ b/src/plugins/relay/weechat/relay-weechat-protocol.c
@@ -159,12 +159,171 @@ relay_weechat_protocol_is_sync (struct t_relay_client *ptr_client,
}
/*
+ * Parses PBKDF2 parameters from string with format:
+ *
+ * algorithm:salt:iterations:hash
+ *
+ * where:
+ *
+ * algorithm is "sha256" or "sha512"
+ * salt is the salt in hexadecimal
+ * iterations it the number of iterations (≥ 1)
+ * hash is the hashed password with the parameters above, in hexadecimal
+ */
+
+void
+relay_weechat_protocol_parse_pbkdf2 (const char *parameters,
+ char **algorithm,
+ char **salt,
+ int *salt_size,
+ int *iterations,
+ char **hash_pbkdf2)
+{
+ char **argv, *error;
+ int argc;
+
+ *algorithm = NULL;
+ *salt = NULL;
+ *salt_size = 0;
+ *iterations = 0;
+ *hash_pbkdf2 = NULL;
+
+ if (!parameters)
+ return;
+
+ argv = weechat_string_split (parameters, ":", NULL, 0, 0, &argc);
+
+ if (!argv || (argc < 4))
+ {
+ /* not enough parameters */
+ if (argv)
+ weechat_string_free_split (argv);
+ return;
+ }
+
+ /* parameter 1: algorithm */
+ if ((strcmp (argv[0], "sha256") == 0)
+ || (strcmp (argv[0], "sha512") == 0))
+ {
+ *algorithm = strdup (argv[0]);
+ }
+
+ /* parameter 2: salt */
+ *salt = malloc (strlen (argv[1]) + 1);
+ if (*salt)
+ *salt_size = weechat_string_base_decode (16, argv[1], *salt);
+
+ /* parameter 3: iterations */
+ *iterations = (int)strtol (argv[2], &error, 10);
+ if (!error || error[0])
+ *iterations = 0;
+
+ /* parameter 4: the PBKDF2 hash */
+ *hash_pbkdf2 = strdup (argv[3]);
+
+ weechat_string_free_split (argv);
+}
+
+/*
+ * Checks if hashed password received is valid.
+ *
+ * Format of hash_password is: algorithm:hash
+ *
+ * Returns 1 if the hashed password is valid, otherwise 0.
+ */
+
+int
+relay_weechat_protocol_check_hash (const char *hashed_password,
+ const char *password)
+{
+ const char *pos_hash;
+ char *hash_algo, hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
+ char *hash_pbkdf2_algo, *salt, *hash_pbkdf2;
+ int rc, hash_size, salt_size, iterations;
+
+ rc = 0;
+
+ if (!hashed_password || !password)
+ goto end;
+
+ pos_hash = strchr (hashed_password, ':');
+ if (!pos_hash)
+ goto end;
+
+ hash_algo = weechat_strndup (hashed_password, pos_hash - hashed_password);
+ if (!hash_algo)
+ goto end;
+
+ pos_hash++;
+
+ if ((strcmp (hash_algo, "sha256") == 0)
+ || (strcmp (hash_algo, "sha512") == 0))
+ {
+ if (weechat_crypto_hash (password, strlen (password), hash_algo,
+ hash, &hash_size))
+ {
+ weechat_string_base_encode (16, hash, hash_size, hash_hexa);
+ if (weechat_strcasecmp (hash_hexa, pos_hash) == 0)
+ rc = 1;
+ }
+ }
+ else if (strcmp (hash_algo, "pbkdf2") == 0)
+ {
+ relay_weechat_protocol_parse_pbkdf2 (pos_hash,
+ &hash_pbkdf2_algo,
+ &salt,
+ &salt_size,
+ &iterations,
+ &hash_pbkdf2);
+ if (hash_pbkdf2_algo && salt && (salt_size > 0) && (iterations > 0)
+ && hash_pbkdf2)
+ {
+ if (weechat_crypto_hash_pbkdf2 (password, strlen (password),
+ hash_pbkdf2_algo,
+ salt, salt_size,
+ iterations,
+ hash, &hash_size))
+ {
+ weechat_string_base_encode (16, hash, hash_size, hash_hexa);
+ if (weechat_strcasecmp (hash_hexa, hash_pbkdf2) == 0)
+ rc = 1;
+ }
+ }
+ if (hash_pbkdf2_algo)
+ free (hash_pbkdf2_algo);
+ if (salt)
+ free (salt);
+ if (hash_pbkdf2)
+ free (hash_pbkdf2);
+ }
+
+ free (hash_algo);
+
+end:
+ return rc;
+}
+
+/*
* Callback for command "init" (from client).
*
+ * Format is: init arg1=value1,arg2=value2
+ *
+ * Allowed arguments:
+ * password plain text password (recommended with SSL only)
+ * password_hash hashed password, value is: algorithm:[parameters:]hash
+ * supported algorithms: sha256, sha512 and pbkdf2
+ * for pbkdf2, parameters are: algorithm, salt, iterations
+ * hash is given in hexadecimal
+ * totp time-based one time password used as secondary
+ * authentication factor
+ * compression zlib (default) or off
+ *
* Message looks like:
* init password=mypass
* init password=mypass,compression=zlib
* init password=mypass,compression=off
+ * init password_hash=sha256:71c480df93d6ae2f1efad1447c66c9…,totp=123456
+ * init password_hash=pbkdf2:sha256:414232…:100000:01757d53157c…,totp=123456
*/
RELAY_WEECHAT_PROTOCOL_CALLBACK(init)
@@ -201,6 +360,15 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(init)
if (password && (strcmp (password, pos) == 0))
RELAY_WEECHAT_DATA(client, password_ok) = 1;
}
+ else if (strcmp (options[i], "password_hash") == 0)
+ {
+ password_received = 1;
+ if (password
+ && relay_weechat_protocol_check_hash (pos, password))
+ {
+ RELAY_WEECHAT_DATA(client, password_ok) = 1;
+ }
+ }
else if (strcmp (options[i], "totp") == 0)
{
totp_received = 1;