@@ -38,6 +38,52 @@ constexpr size_t PBKDF2_HASH_LENGTH= ED25519_KEY_LENGTH;
3838constexpr size_t CLIENT_RESPONSE_LENGTH = CHALLENGE_SCRAMBLE_LENGTH
3939 + ED25519_SIG_LENGTH ;
4040
41+ constexpr unsigned int PARSEC_ITERATIONS_DEFAULT = 1u << 18 ;
42+ constexpr unsigned int PARSEC_ITERATIONS_MIN = 1u << 10 ;
43+ constexpr unsigned int PARSEC_ITERATIONS_MAX = 1u << 19 ;
44+ constexpr unsigned int PARSEC_ITERATIONS_STEP = 1u ;
45+ constexpr unsigned int ITER_FACTOR_BASE_VAL = 10u ;
46+
47+ static unsigned int iterations= PARSEC_ITERATIONS_DEFAULT ;
48+
49+ static inline unsigned int round_to_power_of_two (const unsigned int x) {
50+ unsigned int p = 1 ;
51+ while (p < x)
52+ p <<= 1 ;
53+ return p;
54+ }
55+
56+
57+ static inline unsigned int log_2_of_power_of_2 (const unsigned int x) {
58+ // function will not work correctly for non power of 2 unsigned integers
59+ unsigned int p = 0 ;
60+ while ((1u << p) != x)
61+ p++;
62+ return p;
63+ }
64+
65+
66+ static void update_parsec_iterations (MYSQL_THD thd,
67+ struct st_mysql_sys_var *var __attribute__ ((unused)),
68+ void *var_ptr __attribute__((unused)), const void *save)
69+ {
70+ unsigned int iterations_user_input= *(unsigned int *) save;
71+ iterations= round_to_power_of_two (iterations_user_input);
72+ if (iterations != iterations_user_input)
73+ my_printf_error (ER_WRONG_VALUE_FOR_VAR , " parsec: parsec_iterations rounded up to %d (next supported value)" ,
74+ ME_WARNING , iterations);
75+ }
76+
77+ static MYSQL_SYSVAR_UINT (iterations, iterations, PLUGIN_VAR_NOCMDOPT ,
78+ " Number of iterations to be used when generating the key corresponding to the password" ,
79+ NULL , update_parsec_iterations, PARSEC_ITERATIONS_DEFAULT , PARSEC_ITERATIONS_MIN ,
80+ PARSEC_ITERATIONS_MAX , PARSEC_ITERATIONS_STEP );
81+
82+ static struct st_mysql_sys_var * system_vars[] = {
83+ MYSQL_SYSVAR (iterations),
84+ NULL
85+ };
86+
4187constexpr size_t base64_length (size_t input_length)
4288{
4389 return ((input_length + 2 ) / 3 ) * 4 ; // with padding
@@ -95,7 +141,7 @@ int compute_derived_key(const char* password, size_t pass_len,
95141{
96142 assert (params->algorithm == ' P' );
97143 int ret = PKCS5_PBKDF2_HMAC (password, (int )pass_len, params->salt ,
98- sizeof (params->salt ), 1024 << params->iterations ,
144+ sizeof (params->salt ), 1024u << params->iterations ,
99145 EVP_sha512 (), PBKDF2_HASH_LENGTH , derived_key);
100146 if (ret == 0 )
101147 return print_ssl_error ();
@@ -176,7 +222,7 @@ int hash_password(const char *password, size_t password_length,
176222
177223 Passwd_in_memory memory;
178224 memory.algorithm = ' P' ;
179- memory.iterations = 0 ;
225+ memory.iterations = log_2_of_power_of_2 (iterations) - ITER_FACTOR_BASE_VAL ;
180226 my_random_bytes (memory.salt , sizeof (memory.salt ));
181227
182228 uchar derived_key[PBKDF2_HASH_LENGTH ];
@@ -204,10 +250,11 @@ int digest_to_binary(const char *hash, size_t hash_length,
204250{
205251 auto stored= (Passwd_as_stored*)hash;
206252 auto memory= (Passwd_in_memory*)out;
253+ const uchar ITER_MAX_VAL = ' 0' + (log_2_of_power_of_2 (PARSEC_ITERATIONS_MAX ) - ITER_FACTOR_BASE_VAL );
207254
208255 if (hash_length != sizeof (*stored) || *out_length < sizeof (*memory) ||
209256 stored->algorithm != ' P' ||
210- stored->iterations < ' 0' || stored->iterations > ' 3 ' ||
257+ stored->iterations < ' 0' || stored->iterations > ITER_MAX_VAL ||
211258 stored->colon != ' :' || stored->colon2 != ' :' )
212259 {
213260 my_printf_error (ER_PASSWD_LENGTH , " Wrong ext-salt format" , 0 );
@@ -313,7 +360,7 @@ maria_declare_plugin(auth_parsec)
313360 NULL ,
314361 0x0100 ,
315362 NULL ,
316- NULL ,
363+ system_vars ,
317364 " 1.0" ,
318365 MariaDB_PLUGIN_MATURITY_GAMMA
319366}
0 commit comments