api: add function crypto_hmac (issue #1628)

This commit is contained in:
Sébastien Helleu 2021-06-01 20:28:24 +02:00
parent 6ac6cf7293
commit 5cffb7179f
12 changed files with 434 additions and 29 deletions

View File

@ -26,6 +26,7 @@ New features::
* core: add options to customize commands executed on system signals received (SIGHUP, SIGQUIT, SIGTERM, SIGUSR1, SIGUSR2) (issue #1595)
* core: quit WeeChat by default when signal SIGHUP is received in normal run, reload configuration in weechat-headless (issue #1595)
* core: add signals "cursor_start" and "cursor_end"
* api: add function crypto_hmac (issue #1628)
* api: add translated string in evaluation of expressions with "translate:xxx"
* api: add evaluation of WeeChat directories with "${weechat_xxx_dir}" in evaluated strings
* api: add optional key "directory" in hashtable options of function/modifier string_eval_path_home

View File

@ -3626,6 +3626,54 @@ rc = weechat_crypto_hash_pbkdf2 (data, strlen (data), "sha256", salt, strlen (sa
[NOTE]
This function is not available in scripting API.
==== crypto_hmac
_WeeChat ≥ 3.2._
Compute keyed-hash message authentication code (HMAC).
Prototype:
[source,C]
----
int weechat_crypto_hmac (const void *key, int key_size, const void *message, int message_size,
int hash_algo, void *hash, int *hash_size);
----
Arguments:
* _key_: the key
* _key_size_: number of bytes in _key_
* _message_: the message
* _message_size_: number of bytes in _message_
* _hash_algo_: the hash algorithm, see table in function
<<crypto_hash_algorithms,crypto_hash>>
* _hash_: pointer to the hash variable, which is used to store the resulting hash
(the buffer must be large enough, according to the algorithm, see table
in function <<crypto_hash_algorithms,crypto_hash>>)
* _hash_size_: pointer to a variable used to store the size of the hash computed
(in bytes) (can be NULL)
Return value:
* 1 if OK, 0 if error
C example:
[source,C]
----
const char *key = "the key";
const char *message = "the message";
char hash[256 / 8];
int rc, hash_size;
rc = weechat_crypto_hmac (key, strlen (key), message, strlen (message), "sha256", hash, &hash_size);
/* rc == 1, hash_size == 32 and hash is a buffer with:
47 36 67 02 fc bc b1 97 a4 25 e6 7a b9 52 92 bd 15 9a 66 91 9c fb 94 b0 b4 9a 39 cb c0 24 2d 7b */
----
[NOTE]
This function is not available in scripting API.
[[directories]]
=== Directories

View File

@ -3687,6 +3687,56 @@ rc = weechat_crypto_hash_pbkdf2 (data, strlen (data), "sha256", salt, strlen (sa
[NOTE]
Cette fonction n'est pas disponible dans l'API script.
==== crypto_hmac
_WeeChat ≥ 3.2._
Calculer le code d'authentification d'une empreinte cryptographique de message
avec clé (HMAC).
Prototype :
[source,C]
----
int weechat_crypto_hmac (const void *key, int key_size, const void *message, int message_size,
int hash_algo, void *hash, int *hash_size);
----
Paramètres :
* _key_ : la clé
* _key_size_ : nombre d'octets dans _key_
* _message_ : le message
* _message_size_ : nombre d'octets dans _message_
* _hash_algo_ : l'algorithme de hachage, voir le tableau dans la fonction
<<crypto_hash_algorithms,crypto_hash>>
* _hash_ : pointeur vers la variable de hachage, qui est utilisée pour stocker
le résultat du hachage (le tampon doit être suffisamment grand, selon
l'algorithme, voir le tableau dans la fonction
<<crypto_hash_algorithms,crypto_hash>>)
* _hash_size_ : pointeur vers une variable utiliser pour stocker la longueur
du résultat du hachage (en octets) (peut être NULL)
Valeur de retour :
* 1 si OK, 0 si erreur
Exemple en C :
[source,C]
----
const char *key = "the key";
const char *message = "the message";
char hash[256 / 8];
int rc, hash_size;
rc = weechat_crypto_hmac (key, strlen (key), message, strlen (message), "sha256", hash, &hash_size);
/* rc == 1, hash_size == 32 et hash est un tampon avec :
47 36 67 02 fc bc b1 97 a4 25 e6 7a b9 52 92 bd 15 9a 66 91 9c fb 94 b0 b4 9a 39 cb c0 24 2d 7b */
----
[NOTE]
Cette fonction n'est pas disponible dans l'API script.
[[directories]]
=== Répertoires

View File

@ -3764,6 +3764,55 @@ Questa funzione non è disponibile nelle API per lo scripting.
Alcune funzioni legate alle cartelle.
// TRANSLATION MISSING
==== crypto_hmac
_WeeChat ≥ 3.2._
Compute keyed-hash message authentication code (HMAC).
Prototipo:
[source,C]
----
int weechat_crypto_hmac (const void *key, int key_size, const void *message, int message_size,
int hash_algo, void *hash, int *hash_size);
----
Argomenti:
* _key_: the key
* _key_size_: number of bytes in _key_
* _message_: the message
* _message_size_: number of bytes in _message_
* _hash_algo_: the hash algorithm, see table in function
<<crypto_hash_algorithms,crypto_hash>>
* _hash_: pointer to the hash variable, which is used to store the resulting hash
(the buffer must be large enough, according to the algorithm, see table
in function <<crypto_hash_algorithms,crypto_hash>>)
* _hash_size_: pointer to a variable used to store the size of the hash computed
(in bytes) (can be NULL)
Valore restituito:
* 1 if OK, 0 if error
Esempio in C:
[source,C]
----
const char *key = "the key";
const char *message = "the message";
char hash[256 / 8];
int rc, hash_size;
rc = weechat_crypto_hmac (key, strlen (key), message, strlen (message), "sha256", hash, &hash_size);
/* rc == 1, hash_size == 32 and hash is a buffer with:
47 36 67 02 fc bc b1 97 a4 25 e6 7a b9 52 92 bd 15 9a 66 91 9c fb 94 b0 b4 9a 39 cb c0 24 2d 7b */
----
[NOTE]
Questa funzione non è disponibile nelle API per lo scripting.
==== mkdir_home
// TRANSLATION MISSING

View File

@ -3670,6 +3670,55 @@ rc = weechat_crypto_hash_pbkdf2 (data, strlen (data), "sha256", salt, strlen (sa
[NOTE]
スクリプト API ではこの関数を利用できません。
// TRANSLATION MISSING
==== crypto_hmac
_WeeChat バージョン 3.2 以上で利用可。_
Compute keyed-hash message authentication code (HMAC).
プロトタイプ:
[source,C]
----
int weechat_crypto_hmac (const void *key, int key_size, const void *message, int message_size,
int hash_algo, void *hash, int *hash_size);
----
引数:
* _key_: the key
* _key_size_: number of bytes in _key_
* _message_: the message
* _message_size_: number of bytes in _message_
* _hash_algo_: the hash algorithm, see table in function
<<crypto_hash_algorithms,crypto_hash>>
* _hash_: pointer to the hash variable, which is used to store the resulting hash
(the buffer must be large enough, according to the algorithm, see table
in function <<crypto_hash_algorithms,crypto_hash>>)
* _hash_size_: pointer to a variable used to store the size of the hash computed
(in bytes) (can be NULL)
戻り値:
* 成功した場合は 1、失敗した場合は 0
C 言語での使用例:
[source,C]
----
const char *key = "the key";
const char *message = "the message";
char hash[256 / 8];
int rc, hash_size;
rc = weechat_crypto_hmac (key, strlen (key), message, strlen (message), "sha256", hash, &hash_size);
/* rc == 1, hash_size == 32 and hash is a buffer with:
47 36 67 02 fc bc b1 97 a4 25 e6 7a b9 52 92 bd 15 9a 66 91 9c fb 94 b0 b4 9a 39 cb c0 24 2d 7b */
----
[NOTE]
スクリプト API ではこの関数を利用できません。
[[directories]]
=== ディレクトリ

View File

@ -80,7 +80,7 @@ weecrypto_get_hash_algo (const char *hash_algo)
}
/*
* Computes hash of data using the given algorithm.
* Computes hash of data using the given hash algorithm.
*
* The hash size depends on the algorithm, common ones are:
*
@ -137,6 +137,7 @@ weecrypto_hash (const void *data, int data_size, int hash_algo,
hd_md_opened = 1;
gcry_md_write (*hd_md, data, data_size);
ptr_hash = gcry_md_read (*hd_md, hash_algo);
if (!ptr_hash)
goto hash_end;
@ -216,6 +217,91 @@ hash_pbkdf2_end:
return rc;
}
/*
* Computes keyed-hash message authentication code (HMAC).
*
* The hash size depends on the algorithm, common ones are:
*
* GCRY_MD_CRC32 32 bits == 4 bytes
* GCRY_MD_MD5 128 bits == 16 bytes
* GCRY_MD_SHA1 160 bits == 20 bytes
* GCRY_MD_SHA224 224 bits == 28 bytes
* GCRY_MD_SHA256 256 bits == 32 bytes
* GCRY_MD_SHA384 384 bits == 48 bytes
* GCRY_MD_SHA512 512 bits == 64 bytes
* GCRY_MD_SHA3_224 224 bits == 28 bytes (libgcrypt 1.7.0)
* GCRY_MD_SHA3_256 256 bits == 32 bytes (libgcrypt 1.7.0)
* GCRY_MD_SHA3_384 384 bits == 48 bytes (libgcrypt 1.7.0)
* GCRY_MD_SHA3_512 512 bits == 64 bytes (libgcrypt 1.7.0)
*
* The result hash is stored in "hash" (the buffer must be large enough).
*
* If hash_size is not NULL, the length of hash is stored in *hash_size
* (in bytes).
*
* Returns:
* 1: OK
* 0: error
*/
int
weecrypto_hmac (const void *key, int key_size,
const void *message, int message_size,
int hash_algo,
void *hash, int *hash_size)
{
gcry_md_hd_t *hd_md;
int rc, hd_md_opened, algo_size;
unsigned char *ptr_hash;
rc = 0;
hd_md = NULL;
hd_md_opened = 0;
if (!hash)
goto hmac_end;
if (hash_size)
*hash_size = 0;
if (!key || (key_size < 1) || !message || (message_size < 1))
goto hmac_end;
hd_md = malloc (sizeof (gcry_md_hd_t));
if (!hd_md)
goto hmac_end;
if (gcry_md_open (hd_md, hash_algo, GCRY_MD_FLAG_HMAC) != 0)
goto hmac_end;
hd_md_opened = 1;
if (gcry_md_setkey (*hd_md, key, key_size) != 0)
goto hmac_end;
gcry_md_write (*hd_md, message, message_size);
ptr_hash = gcry_md_read (*hd_md, hash_algo);
if (!ptr_hash)
goto hmac_end;
algo_size = gcry_md_get_algo_dlen (hash_algo);
memcpy (hash, ptr_hash, algo_size);
if (hash_size)
*hash_size = algo_size;
rc = 1;
hmac_end:
if (hd_md)
{
if (hd_md_opened)
gcry_md_close (*hd_md);
free (hd_md);
}
return rc;
}
/*
* Generates a Time-based One-Time Password (TOTP), as described
* in the RFC 6238.
@ -230,22 +316,11 @@ weecrypto_totp_generate_internal (const char *secret, int length_secret,
uint64_t moving_factor, int digits,
char *result)
{
gcry_md_hd_t hd_md;
uint64_t moving_factor_swapped;
unsigned char *ptr_hash;
char hash[20];
int offset, length;
unsigned long bin_code;
if (gcry_md_open (&hd_md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC) != 0)
return 0;
if (gcry_md_setkey (hd_md, secret, length_secret) != 0)
{
gcry_md_close (hd_md);
return 0;
}
moving_factor_swapped = (moving_factor >> 56)
| ((moving_factor << 40) & 0x00FF000000000000)
| ((moving_factor << 24) & 0x0000FF0000000000)
@ -255,19 +330,10 @@ weecrypto_totp_generate_internal (const char *secret, int length_secret,
| ((moving_factor >> 40) & 0x000000000000FF00)
| (moving_factor << 56);
gcry_md_write (hd_md,
&moving_factor_swapped, sizeof (moving_factor_swapped));
ptr_hash = gcry_md_read (hd_md, GCRY_MD_SHA1);
if (!ptr_hash)
{
gcry_md_close (hd_md);
return 0;
}
memcpy (hash, ptr_hash, sizeof (hash));
gcry_md_close (hd_md);
weecrypto_hmac (secret, length_secret,
&moving_factor_swapped, sizeof (moving_factor_swapped),
GCRY_MD_SHA1,
hash, NULL);
offset = hash[19] & 0xf;
bin_code = (hash[offset] & 0x7f) << 24

View File

@ -31,6 +31,10 @@ extern int weecrypto_hash_pbkdf2 (const void *data, int data_size,
const void *salt, int salt_size,
int iterations,
void *hash, int *hash_size);
extern int weecrypto_hmac (const void *key, int key_size,
const void *message, int message_size,
int hash_algo,
void *hash, int *hash_size);
extern char *weecrypto_totp_generate (const char *secret, time_t totp_time,
int digits);
extern int weecrypto_totp_validate (const char *secret, time_t totp_time,

View File

@ -162,6 +162,39 @@ plugin_api_crypto_hash_pbkdf2 (const void *data, int data_size,
iterations, hash, hash_size);
}
/*
* Computes HMAC of key + message using the given algorithm.
*
* Returns:
* 1: OK
* 0: error
*/
int
plugin_api_crypto_hmac (const void *key, int key_size,
const void *message, int message_size,
const char *hash_algo,
void *hash, int *hash_size)
{
int algo;
if (!hash)
return 0;
if (hash_size)
*hash_size = 0;
if (!key || (key_size < 1) || !message || (message_size < 1) || !hash_algo)
return 0;
algo = weecrypto_get_hash_algo (hash_algo);
if (algo == GCRY_MD_NONE)
return 0;
return weecrypto_hmac (key, key_size, message, message_size,
algo, hash, hash_size);
}
/*
* Frees an option.
*/

View File

@ -38,6 +38,10 @@ extern int plugin_api_crypto_hash_pbkdf2 (const void *data, int data_size,
const void *salt, int salt_size,
int iterations,
void *hash, int *hash_size);
extern int plugin_api_crypto_hmac (const void *key, int key_size,
const void *message, int message_size,
const char *hash_algo,
void *hash, int *hash_size);
/* config */
extern void plugin_api_config_file_option_free (struct t_config_option *option);

View File

@ -665,6 +665,7 @@ plugin_load (const char *filename, int init_plugin, int argc, char **argv)
new_plugin->crypto_hash = &plugin_api_crypto_hash;
new_plugin->crypto_hash_pbkdf2 = &plugin_api_crypto_hash_pbkdf2;
new_plugin->crypto_hmac = &plugin_api_crypto_hmac;
new_plugin->mkdir_home = &dir_mkdir_home;
new_plugin->mkdir = &dir_mkdir;

View File

@ -68,7 +68,7 @@ struct timeval;
* please change the date with current one; for a second change at same
* date, increment the 01, otherwise please keep 01.
*/
#define WEECHAT_PLUGIN_API_VERSION "20201004-01"
#define WEECHAT_PLUGIN_API_VERSION "20210601-01"
/* macros for defining plugin infos */
#define WEECHAT_PLUGIN_NAME(__name) \
@ -382,6 +382,9 @@ struct t_weechat_plugin
const void *salt, int salt_size,
int iterations,
void *hash, int *hash_size);
int (*crypto_hmac) (const void *key, int key_size,
const void *message, int message_size,
const char *hash_algo, void *hash, int *hash_size);
/* directories/files */
int (*mkdir_home) (const char *directory, int mode);
@ -1347,6 +1350,14 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
__salt, __salt_size, \
__iterations, \
__hash, __hash_size)
#define weechat_crypto_hmac(__key, __key_size, \
__message, __message_size, \
__hash_algo, \
__hash, __hash_size) \
(weechat_plugin->crypto_hmac)(__key, __key_size, \
__message, __message_size, \
__hash_algo, \
__hash, __hash_size)
/* directories */
#define weechat_mkdir_home(__directory, __mode) \

View File

@ -29,7 +29,8 @@ extern "C"
#include "src/core/wee-crypto.h"
#include "src/core/wee-string.h"
#define DATA_HASH "this is a test of hash function"
/* Hash */
#define DATA_HASH_MSG "this is a test of hash function"
#define DATA_HASH_CRC32 "ef26fe3e"
#define DATA_HASH_MD5 "1197d121af621ac6a63cb8ef6b5dfa30"
#define DATA_HASH_SHA1 "799d818061175b400dc5aaeb14b8d32cdef32ff0"
@ -51,6 +52,8 @@ extern "C"
#define DATA_HASH_SHA3_512 "31dfb5fc8f30ac7007acddc4fce562d408706833d0d2af2" \
"e5f61a179099592927ff7d100e278406c7f98d42575001e26e153b135c21f7ef5b00c8" \
"cef93ca048d"
/* Hash PBKDF2 */
#define DATA_HASH_SALT "this is a salt of 32 bytes xxxxx"
#define DATA_HASH_PBKDF2_SHA1_1000 "85ce23c8873830df8f0a96aa82ae7d7635dad12" \
"7"
@ -60,6 +63,31 @@ extern "C"
"a402af301e1714c25467a32489c773c71eddf5aa39f42823ecc54c9e9b015517b5f3c0" \
"19bae9463a2d8fe527882"
/* HMAC */
#define DATA_HMAC_KEY "secret key"
#define DATA_HMAC_MSG "this is a test of hmac function"
#define DATA_HMAC_CRC32 "3c189d75"
#define DATA_HMAC_MD5 "8148a8e01eb0c6ca42880ea58f50d045"
#define DATA_HMAC_SHA1 "28dea5713c0d48c7638db31050a7ded4308f46fe"
#define DATA_HMAC_SHA224 "f1cf0ccf287a2e35b98414346931396d47ca929c92c48edcc" \
"e8e0b9e"
#define DATA_HMAC_SHA256 "7be1b4281c0d74d4a3838892b1512efa13a25c7a50d7dce47" \
"da070c7e7c65dee"
#define DATA_HMAC_SHA384 "8cd5f4afc602e11f6b3032fd65e906da810ac51aeb7d30f4b" \
"7b495ae3dcc0eede0c5f63d7d2e3688fe658daf4852be67"
#define DATA_HMAC_SHA512 "940e5c280c08cd858f79a6085b4bdc54710ed339dd1008fa2" \
"1643b7bbeea8a5f61c77f395708505461af62776c9cb7be1c263f39055eb8478190cd8" \
"0ea5b0850"
#define DATA_HMAC_SHA3_224 "a08c7f1598ecc7ea54feeb920ef90b3748d59b3203caa74" \
"7316eb2d4"
#define DATA_HMAC_SHA3_256 "21aca280bc1ac1fa261b1169a321eb7a49e38a8ddec66a8" \
"fa2ed9c43d7fae4c5"
#define DATA_HMAC_SHA3_384 "cbf189e8cd31f3c1c5742e2688b13be8e62691952eee374" \
"9523b48bd7a7d1cdf38812cf9a3e52dbb1d0e32a11e478ce7"
#define DATA_HMAC_SHA3_512 "b1eeb16dd18f66cc8886754ac9cf238deea24d9797ceecb" \
"9e0582148bfb6b88f7530d594e80a5a5e22e351a079855983da91b0011dff85ea4a895" \
"e8fde6fd41a"
#define TOTP_SECRET "secretpasswordbase32"
#define WEE_CHECK_HASH(__result_code, __result_hash, \
@ -109,6 +137,30 @@ extern "C"
} \
LONGS_EQUAL(hash_size_expected, hash_size);
#define WEE_CHECK_HMAC(__result_code, __result_hash, \
__key, __key_size, __message, __message_size, \
__hash_algo) \
if (__result_hash) \
{ \
hash_size_expected = string_base16_decode (__result_hash, \
hash_expected); \
} \
else \
{ \
hash_size_expected = 0; \
} \
hash_size = -1; \
LONGS_EQUAL(__result_code, \
weecrypto_hmac (__key, __key_size, \
__message, __message_size, \
__hash_algo, \
hash, &hash_size)); \
if (__result_hash) \
{ \
MEMCMP_EQUAL(hash_expected, hash, hash_size); \
} \
LONGS_EQUAL(hash_size_expected, hash_size);
#define WEE_CHECK_TOTP_GENERATE(__result, __secret, __time, __digits) \
totp = weecrypto_totp_generate (__secret, __time, __digits); \
if (__result == NULL) \
@ -165,7 +217,7 @@ TEST(CoreCrypto, GetHashAlgo)
TEST(CoreCrypto, Hash)
{
const char *data = DATA_HASH;
const char *data = DATA_HASH_MSG;
char hash_expected[4096], hash[4096];
int data_size, hash_size_expected, hash_size;
@ -199,7 +251,7 @@ TEST(CoreCrypto, Hash)
TEST(CoreCrypto, HashPbkdf2)
{
const char *data = DATA_HASH, *salt = DATA_HASH_SALT;
const char *data = DATA_HASH_MSG, *salt = DATA_HASH_SALT;
char hash_expected[4096], hash[4096];
int data_size, salt_size, hash_size_expected, hash_size;
@ -236,6 +288,43 @@ TEST(CoreCrypto, HashPbkdf2)
1000);
}
/*
* Tests functions:
* weecrypto_hmac
*/
TEST(CoreCrypto, Hmac)
{
const char *key = DATA_HMAC_KEY, *msg = DATA_HMAC_MSG;
char hash_expected[4096], hash[4096];
int key_size, msg_size, hash_size_expected, hash_size;
key_size = strlen (key);
msg_size = strlen (msg);
WEE_CHECK_HMAC(0, NULL, NULL, 0, NULL, 0, 0);
WEE_CHECK_HMAC(0, NULL, "key", 0, NULL, 0, 0);
WEE_CHECK_HMAC(0, NULL, NULL, 0, "msg", 0, 0);
WEE_CHECK_HMAC(0, NULL, "key", 0, "msg", 0, 0);
LONGS_EQUAL (0, weecrypto_hmac (key, key_size, msg, msg_size,
GCRY_MD_SHA256, NULL, NULL));
WEE_CHECK_HMAC(1, DATA_HMAC_CRC32, key, key_size, msg, msg_size, GCRY_MD_CRC32);
WEE_CHECK_HMAC(1, DATA_HMAC_MD5, key, key_size, msg, msg_size, GCRY_MD_MD5);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA1, key, key_size, msg, msg_size, GCRY_MD_SHA1);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA224, key, key_size, msg, msg_size, GCRY_MD_SHA224);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA256, key, key_size, msg, msg_size, GCRY_MD_SHA256);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA384, key, key_size, msg, msg_size, GCRY_MD_SHA384);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA512, key, key_size, msg, msg_size, GCRY_MD_SHA512);
#if GCRYPT_VERSION_NUMBER >= 0x010700
WEE_CHECK_HMAC(1, DATA_HMAC_SHA3_224, key, key_size, msg, msg_size, GCRY_MD_SHA3_224);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA3_256, key, key_size, msg, msg_size, GCRY_MD_SHA3_256);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA3_384, key, key_size, msg, msg_size, GCRY_MD_SHA3_384);
WEE_CHECK_HMAC(1, DATA_HMAC_SHA3_512, key, key_size, msg, msg_size, GCRY_MD_SHA3_512);
#endif
}
/*
* Tests functions:
* weecrypto_totp_generate