diff --git a/cmake/ssl.cmake b/cmake/ssl.cmake index b776cc9d6c8..db506d58ac0 100644 --- a/cmake/ssl.cmake +++ b/cmake/ssl.cmake @@ -60,6 +60,7 @@ MACRO (MYSQL_USE_BUNDLED_SSL) SET(HAVE_EncryptAes128Ctr ON CACHE INTERNAL "wolfssl does support AES-CTR") SET(HAVE_EncryptAes128Gcm OFF CACHE INTERNAL "wolfssl does not support AES-GCM") SET(HAVE_X509_check_host ON CACHE INTERNAL "wolfssl does support X509_check_host") + SET(HAVE_hkdf ON CACHE INTERNAL "wolfssl does support EVP_PKEY API") CHANGE_SSL_SETTINGS("bundled") ADD_SUBDIRECTORY(extra/wolfssl) MESSAGE_ONCE(SSL_LIBRARIES "SSL_LIBRARIES = ${SSL_LIBRARIES}") @@ -158,6 +159,8 @@ MACRO (MYSQL_CHECK_SSL) HAVE_EncryptAes128Gcm) CHECK_SYMBOL_EXISTS(X509_check_host "openssl/x509v3.h" HAVE_X509_check_host) + CHECK_SYMBOL_EXISTS(EVP_PKEY_CTX_set_hkdf_md "string.h;stdarg.h;openssl/kdf.h" + HAVE_hkdf) SET(CMAKE_REQUIRED_INCLUDES) SET(CMAKE_REQUIRED_LIBRARIES) SET(CMAKE_REQUIRED_DEFINITIONS) diff --git a/config.h.cmake b/config.h.cmake index e8712d16ba6..5e6c324a07e 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -499,6 +499,7 @@ #cmakedefine HAVE_COMPRESS 1 #cmakedefine HAVE_EncryptAes128Ctr 1 #cmakedefine HAVE_EncryptAes128Gcm 1 +#cmakedefine HAVE_hkdf 1 /* Stuff that always need to be defined (compile breaks without it) diff --git a/mysql-test/main/func_kdf,old.rdiff b/mysql-test/main/func_kdf,old.rdiff new file mode 100644 index 00000000000..18c9dde07a6 --- /dev/null +++ b/mysql-test/main/func_kdf,old.rdiff @@ -0,0 +1,64 @@ +--- main/func_kdf.result ++++ main/func_kdf.reject +@@ -21,10 +21,14 @@ + 48565B49B42FBF88537AFA1D4C0FA2C6 + select hex(kdf('foo', 'bar', 'info', 'hkdf')); + hex(kdf('foo', 'bar', 'info', 'hkdf')) +-710583081D40A55F0B573A76E02D8975 ++NULL ++Warnings: ++Warning 1235 This version of MariaDB doesn't yet support 'kdf(..., 'hkdf')' + select hex(kdf('foo', 'bar', 'infa', 'hkdf')); + hex(kdf('foo', 'bar', 'infa', 'hkdf')) +-612875F859CFB4EE0DFEFF9F2A18E836 ++NULL ++Warnings: ++Warning 1235 This version of MariaDB doesn't yet support 'kdf(..., 'hkdf')' + select hex(kdf('foo', 'bar', 'info', 'pbkdf2_hmac')); + hex(kdf('foo', 'bar', 'info', 'pbkdf2_hmac')) + NULL +@@ -55,7 +59,9 @@ + NULL + select hex(kdf('foo', 'bar', NULL, 'hkdf')); + hex(kdf('foo', 'bar', NULL, 'hkdf')) +-4AFD0088E56CAF7CB5C94F6C101D58D5 ++NULL ++Warnings: ++Warning 1235 This version of MariaDB doesn't yet support 'kdf(..., 'hkdf')' + select hex(kdf('foo', 'bar', NULL, 'pbkdf2_hmac')); + hex(kdf('foo', 'bar', NULL, 'pbkdf2_hmac')) + NULL +@@ -81,10 +87,14 @@ + set @@block_encryption_mode='aes-192-cbc'; + select hex(kdf('foo', 'bar', 'info', 'hkdf')); + hex(kdf('foo', 'bar', 'info', 'hkdf')) +-710583081D40A55F0B573A76E02D8975AA11A4595954C0A1 ++NULL ++Warnings: ++Warning 1235 This version of MariaDB doesn't yet support 'kdf(..., 'hkdf')' + select hex(kdf('foo', 'bar', 'info', 'hkdf', 256)); + hex(kdf('foo', 'bar', 'info', 'hkdf', 256)) +-710583081D40A55F0B573A76E02D8975AA11A4595954C0A1487D6D33ABAB93C3 ++NULL ++Warnings: ++Warning 1235 This version of MariaDB doesn't yet support 'kdf(..., 'hkdf')' + select hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac')); + hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac')) + 430D4780B57254EF39EE13CE53DB381A552151AA62A9FA92 +@@ -110,10 +120,14 @@ + Warning 3047 Invalid argument error: 0 in function kdf. + select length(kdf('foo', 'bar', 'info', 'hkdf', 32768)); + length(kdf('foo', 'bar', 'info', 'hkdf', 32768)) +-4096 ++NULL ++Warnings: ++Warning 1235 This version of MariaDB doesn't yet support 'kdf(..., 'hkdf')' + select length(kdf('foo', 'bar', 'info', 'hkdf', 65536)); + length(kdf('foo', 'bar', 'info', 'hkdf', 65536)) +-8192 ++NULL ++Warnings: ++Warning 1235 This version of MariaDB doesn't yet support 'kdf(..., 'hkdf')' + select length(kdf('foo', 'bar', 'info', 'hkdf', 65537)); + length(kdf('foo', 'bar', 'info', 'hkdf', 65537)) + NULL diff --git a/mysql-test/main/func_kdf.combinations b/mysql-test/main/func_kdf.combinations new file mode 100644 index 00000000000..2adc887937e --- /dev/null +++ b/mysql-test/main/func_kdf.combinations @@ -0,0 +1,4 @@ +[new] + +[old] +# remove when no longer building with OpenSSL 1.0 diff --git a/mysql-test/main/func_kdf.result b/mysql-test/main/func_kdf.result new file mode 100644 index 00000000000..3dc1fd23020 --- /dev/null +++ b/mysql-test/main/func_kdf.result @@ -0,0 +1,158 @@ +# +# MDEV-31474 KDF() function +# +select hex(kdf('foo', 'bar')); +hex(kdf('foo', 'bar')) +76BA6DEC5C3F6A60704D730A2A4BAA1C +select hex(kdf('foo', 'bar')); +hex(kdf('foo', 'bar')) +76BA6DEC5C3F6A60704D730A2A4BAA1C +select hex(kdf('faa', 'bar')); +hex(kdf('faa', 'bar')) +62A8C6FD3E6FDA7ECE6D37CF1C95E3CC +select hex(kdf('foo', 'bor')); +hex(kdf('foo', 'bor')) +F0FE3B0884C9733A520EC8C2EE711137 +select hex(kdf('foo', 'bar', 10)); +hex(kdf('foo', 'bar', 10)) +1D25A9E01C2078FF10DECEC874B3F21E +select hex(kdf('foo', 'bar', 11)); +hex(kdf('foo', 'bar', 11)) +48565B49B42FBF88537AFA1D4C0FA2C6 +select hex(kdf('foo', 'bar', 'info', 'hkdf')); +hex(kdf('foo', 'bar', 'info', 'hkdf')) +710583081D40A55F0B573A76E02D8975 +select hex(kdf('foo', 'bar', 'infa', 'hkdf')); +hex(kdf('foo', 'bar', 'infa', 'hkdf')) +612875F859CFB4EE0DFEFF9F2A18E836 +select hex(kdf('foo', 'bar', 'info', 'pbkdf2_hmac')); +hex(kdf('foo', 'bar', 'info', 'pbkdf2_hmac')) +NULL +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'info' +Warning 3047 Invalid argument error: 0 in function kdf. +select hex(kdf('foo', 'bar', -1, 'pbkdf2_hmac')); +hex(kdf('foo', 'bar', -1, 'pbkdf2_hmac')) +NULL +Warnings: +Warning 3047 Invalid argument error: -1 in function kdf. +select hex(kdf('foo', 'bar', 0, 'pbkdf2_hmac')); +hex(kdf('foo', 'bar', 0, 'pbkdf2_hmac')) +NULL +Warnings: +Warning 3047 Invalid argument error: 0 in function kdf. +select hex(kdf('foo', 'bar', 1, 'pbkdf2_hmac')); +hex(kdf('foo', 'bar', 1, 'pbkdf2_hmac')) +DB658012DC3E52AEC1F4933C280B6E10 +select hex(kdf('foo', 'bar', 10, 'pbkdf2_hmac')); +hex(kdf('foo', 'bar', 10, 'pbkdf2_hmac')) +1D25A9E01C2078FF10DECEC874B3F21E +select hex(kdf(NULL, 'bar')); +hex(kdf(NULL, 'bar')) +NULL +select hex(kdf('foo', NULL)); +hex(kdf('foo', NULL)) +NULL +select hex(kdf('foo', 'bar', NULL, 'hkdf')); +hex(kdf('foo', 'bar', NULL, 'hkdf')) +4AFD0088E56CAF7CB5C94F6C101D58D5 +select hex(kdf('foo', 'bar', NULL, 'pbkdf2_hmac')); +hex(kdf('foo', 'bar', NULL, 'pbkdf2_hmac')) +NULL +select hex(kdf('foo', 'bar', 2000, NULL)); +hex(kdf('foo', 'bar', 2000, NULL)) +NULL +select hex(kdf('foo', 'bar', 2000, 'foo')); +hex(kdf('foo', 'bar', 2000, 'foo')) +NULL +Warnings: +Warning 3047 Invalid argument error: 'foo' in function kdf. +select hex(kdf('foo', 'bar', 2000, '\n\n\n\0!!!')); +hex(kdf('foo', 'bar', 2000, '\n\n\n\0!!!')) +NULL +Warnings: +Warning 3047 Invalid argument error: ' + + +\0000!!!' in function kdf. +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', NULL)); +hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', NULL)) +NULL +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', -8)); +hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', -8)) +NULL +Warnings: +Warning 3047 Invalid argument error: -8 in function kdf. +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', 10)); +hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', 10)) +NULL +Warnings: +Warning 3047 Invalid argument error: 10 in function kdf. +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', 16)); +hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', 16)) +76BA +set @@block_encryption_mode='aes-192-cbc'; +select hex(kdf('foo', 'bar', 'info', 'hkdf')); +hex(kdf('foo', 'bar', 'info', 'hkdf')) +710583081D40A55F0B573A76E02D8975AA11A4595954C0A1 +select hex(kdf('foo', 'bar', 'info', 'hkdf', 256)); +hex(kdf('foo', 'bar', 'info', 'hkdf', 256)) +710583081D40A55F0B573A76E02D8975AA11A4595954C0A1487D6D33ABAB93C3 +select hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac')); +hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac')) +430D4780B57254EF39EE13CE53DB381A552151AA62A9FA92 +select hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac', 256)); +hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac', 256)) +430D4780B57254EF39EE13CE53DB381A552151AA62A9FA922B9949DF270AE10C +set @key=kdf('password', 'salt', 2048); +select hex(aes_encrypt('secret', @key, '1234123412341234')); +hex(aes_encrypt('secret', @key, '1234123412341234')) +9EED553CDDEE426D5635EF559E015ECA +select aes_decrypt(x'9EED553CDDEE426D5635EF559E015ECA', @key, '1234123412341234'); +aes_decrypt(x'9EED553CDDEE426D5635EF559E015ECA', @key, '1234123412341234') +secret +select length(kdf('foo', 'bar', 'info', 'hkdf', -1)); +length(kdf('foo', 'bar', 'info', 'hkdf', -1)) +NULL +Warnings: +Warning 3047 Invalid argument error: -1 in function kdf. +select length(kdf('foo', 'bar', 'info', 'hkdf', 0)); +length(kdf('foo', 'bar', 'info', 'hkdf', 0)) +NULL +Warnings: +Warning 3047 Invalid argument error: 0 in function kdf. +select length(kdf('foo', 'bar', 'info', 'hkdf', 32768)); +length(kdf('foo', 'bar', 'info', 'hkdf', 32768)) +4096 +select length(kdf('foo', 'bar', 'info', 'hkdf', 65536)); +length(kdf('foo', 'bar', 'info', 'hkdf', 65536)) +8192 +select length(kdf('foo', 'bar', 'info', 'hkdf', 65537)); +length(kdf('foo', 'bar', 'info', 'hkdf', 65537)) +NULL +Warnings: +Warning 3047 Invalid argument error: 65537 in function kdf. +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', -1)); +length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', -1)) +NULL +Warnings: +Warning 3047 Invalid argument error: -1 in function kdf. +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 0)); +length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 0)) +NULL +Warnings: +Warning 3047 Invalid argument error: 0 in function kdf. +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 32768)); +length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 32768)) +4096 +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 65536)); +length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 65536)) +8192 +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 65537)); +length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 65537)) +NULL +Warnings: +Warning 3047 Invalid argument error: 65537 in function kdf. +# +# End of 11.3 tests +# diff --git a/mysql-test/main/func_kdf.test b/mysql-test/main/func_kdf.test new file mode 100644 index 00000000000..872052fca6c --- /dev/null +++ b/mysql-test/main/func_kdf.test @@ -0,0 +1,57 @@ +--echo # +--echo # MDEV-31474 KDF() function +--echo # +select hex(kdf('foo', 'bar')); +select hex(kdf('foo', 'bar')); # same result every time +select hex(kdf('faa', 'bar')); +select hex(kdf('foo', 'bor')); + +select hex(kdf('foo', 'bar', 10)); +select hex(kdf('foo', 'bar', 11)); + +select hex(kdf('foo', 'bar', 'info', 'hkdf')); +select hex(kdf('foo', 'bar', 'infa', 'hkdf')); +select hex(kdf('foo', 'bar', 'info', 'pbkdf2_hmac')); +select hex(kdf('foo', 'bar', -1, 'pbkdf2_hmac')); +select hex(kdf('foo', 'bar', 0, 'pbkdf2_hmac')); +select hex(kdf('foo', 'bar', 1, 'pbkdf2_hmac')); +select hex(kdf('foo', 'bar', 10, 'pbkdf2_hmac')); + +select hex(kdf(NULL, 'bar')); +select hex(kdf('foo', NULL)); +select hex(kdf('foo', 'bar', NULL, 'hkdf')); +select hex(kdf('foo', 'bar', NULL, 'pbkdf2_hmac')); +select hex(kdf('foo', 'bar', 2000, NULL)); +select hex(kdf('foo', 'bar', 2000, 'foo')); +select hex(kdf('foo', 'bar', 2000, '\n\n\n\0!!!')); +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', NULL)); +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', -8)); +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', 10)); +select hex(kdf('foo', 'bar', 1000, 'pbkdf2_hmac', 16)); + +set @@block_encryption_mode='aes-192-cbc'; +select hex(kdf('foo', 'bar', 'info', 'hkdf')); +select hex(kdf('foo', 'bar', 'info', 'hkdf', 256)); +select hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac')); +select hex(kdf('foo', 'bar', 2000, 'pbkdf2_hmac', 256)); + +set @key=kdf('password', 'salt', 2048); +select hex(aes_encrypt('secret', @key, '1234123412341234')); +select aes_decrypt(x'9EED553CDDEE426D5635EF559E015ECA', @key, '1234123412341234'); + +select length(kdf('foo', 'bar', 'info', 'hkdf', -1)); +select length(kdf('foo', 'bar', 'info', 'hkdf', 0)); +select length(kdf('foo', 'bar', 'info', 'hkdf', 32768)); +select length(kdf('foo', 'bar', 'info', 'hkdf', 65536)); +select length(kdf('foo', 'bar', 'info', 'hkdf', 65537)); + +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', -1)); +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 0)); +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 32768)); +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 65536)); +select length(kdf('foo', 'bar', 100, 'pbkdf2_hmac', 65537)); + +--echo # +--echo # End of 11.3 tests +--echo # + diff --git a/mysql-test/suite.pm b/mysql-test/suite.pm index f30cc5ec431..0f562bed4e0 100644 --- a/mysql-test/suite.pm +++ b/mysql-test/suite.pm @@ -84,6 +84,8 @@ sub skip_combinations { $skip{'main/ssl_7937.combinations'} = [ 'x509v3' ] unless $ssl_lib =~ /WolfSSL/ or $openssl_ver ge "1.0.2"; + $skip{'main/func_kdf.combinations'} = [ $ssl_lib =~ /OpenSSL 1\.0\./ ? 'new' : 'old' ]; + $skip{'main/ssl_verify_ip.test'} = 'x509v3 support required' unless $openssl_ver ge "1.0.2"; diff --git a/sql/item_create.cc b/sql/item_create.cc index 46706823ccf..4f0df8f732d 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -155,6 +155,20 @@ protected: }; +class Create_func_kdf : public Create_native_func +{ +public: + virtual Item *create_native(THD *thd, const LEX_CSTRING *name, + List *item_list); + + static Create_func_kdf s_singleton; + +protected: + Create_func_kdf() = default; + virtual ~Create_func_kdf() = default; +}; + + class Create_func_asin : public Create_func_arg1 { public: @@ -2986,6 +3000,32 @@ Create_func_aes_decrypt::create_native(THD *thd, const LEX_CSTRING *name, } +Create_func_kdf Create_func_kdf::s_singleton; + +Item* +Create_func_kdf::create_native(THD *thd, const LEX_CSTRING *name, + List *item_list) +{ + uint arg_count= item_list->elements; + Item *a[5]; + for (uint i=0; i < MY_MIN(array_elements(a), arg_count); i++) + a[i]= item_list->pop(); + switch (arg_count) + { + case 2: + return new (thd->mem_root) Item_func_kdf(thd, a[0], a[1]); + case 3: + return new (thd->mem_root) Item_func_kdf(thd, a[0], a[1], a[2]); + case 4: + return new (thd->mem_root) Item_func_kdf(thd, a[0], a[1], a[2], a[3]); + case 5: + return new (thd->mem_root) Item_func_kdf(thd, a[0], a[1], a[2], a[3], a[4]); + } + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str); + return NULL; +} + + Create_func_asin Create_func_asin::s_singleton; Item* @@ -5941,6 +5981,7 @@ const Native_func_registry func_array[] = { { STRING_WITH_LEN("JSON_UNQUOTE") }, BUILDER(Create_func_json_unquote)}, { { STRING_WITH_LEN("JSON_VALID") }, BUILDER(Create_func_json_valid)}, { { STRING_WITH_LEN("JSON_VALUE") }, BUILDER(Create_func_json_value)}, + { { STRING_WITH_LEN("KDF") }, BUILDER(Create_func_kdf)}, { { STRING_WITH_LEN("LAST_DAY") }, BUILDER(Create_func_last_day)}, { { STRING_WITH_LEN("LAST_INSERT_ID") }, BUILDER(Create_func_last_insert_id)}, { { STRING_WITH_LEN("LCASE") }, BUILDER(Create_func_lcase)}, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d35aa57568b..a29ef6c4bca 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -56,6 +56,10 @@ C_MODE_END #include "sql_statistics.h" #include "strfunc.h" +#ifdef HAVE_hkdf +#include +#endif + /* fmtlib include (https://fmt.dev/). */ #define FMT_STATIC_THOUSANDS_SEPARATOR ',' #define FMT_HEADER_ONLY 1 @@ -434,6 +438,122 @@ bool Item_func_aes_decrypt::fix_length_and_dec(THD *thd) return FALSE; } +bool Item_func_kdf::fix_length_and_dec(THD *thd) +{ + if (arg_count > 4 && args[4]->const_item()) + { + if (((key_length= (uint)args[4]->val_int()) % 8) || key_length > 65536) + key_length= 0; + } + else if (arg_count <= 4) + key_length= block_encryption_mode_to_key_length(thd->variables.block_encryption_mode); + else + key_length= 0; + key_length/= 8; + max_length= key_length ? key_length : 256/8; + set_maybe_null(); + return FALSE; +} + +static void invalid_argument_error(const char *func, const char *val) +{ + THD *thd= current_thd; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_STD_INVALID_ARGUMENT, ER_THD(thd, ER_STD_INVALID_ARGUMENT), + val, func); +} + +String *Item_func_kdf::val_str(String *buf) +{ + // KDF(key_str, salt [, {info | iterations} [, kdf_name [, width ]]]) + DBUG_ASSERT(fixed()); + StringBuffer<80> key_buf, salt_buf; + String *key= args[0]->val_str(&key_buf); + String *salt= args[1]->val_str(&salt_buf); + bool use_hkdf= false; + size_t klen= key_length; + bool ok= false; + + if (!key || !salt) + goto ret_null; + + if (arg_count > 3) + { + if (String *s= args[3]->val_str(buf)) + { + if (strcasecmp(s->c_ptr(), "hkdf") == 0) + use_hkdf= true; + else if (strcasecmp(s->c_ptr(), "pbkdf2_hmac") != 0) + { + invalid_argument_error(func_name(), ErrConvStringQ(s).ptr()); + goto ret_null; + } + } + else + goto ret_null; + } + if (!klen) + { + klen= args[4]->val_int(); + if (!klen || klen % 8 || klen > 65536) + { + if (!args[4]->null_value) + invalid_argument_error(func_name(), + ErrConvInteger({(ssize_t)klen, args[4]->unsigned_flag}).ptr()); + goto ret_null; + } + klen/= 8; + } + buf->reserve(klen); + buf->length(klen); + + if (use_hkdf) + { +#ifdef HAVE_hkdf + StringBuffer<80> info_buf; + String *info= arg_count > 2 ? args[2]->val_str(&info_buf) : 0; + + EVP_PKEY_CTX *ctx= EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + ok= EVP_PKEY_derive_init(ctx) > 0 && + EVP_PKEY_CTX_set_hkdf_md(ctx, EVP_sha512()) > 0 && + EVP_PKEY_CTX_set1_hkdf_key(ctx, (const uchar*)key->ptr(), key->length()) > 0 && + EVP_PKEY_CTX_set1_hkdf_salt(ctx, (const uchar*)salt->ptr(), salt->length()) > 0 && + (!info || EVP_PKEY_CTX_add1_hkdf_info(ctx, (const uchar*)info->ptr(), info->length()) > 0) && + EVP_PKEY_derive(ctx, (uchar*)buf->ptr(), &klen) > 0; + + EVP_PKEY_CTX_free(ctx); +#else + THD *thd= current_thd; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_NOT_SUPPORTED_YET, ER_THD(thd, ER_NOT_SUPPORTED_YET), + "kdf(..., 'hkdf')"); +#endif + } + else + { + longlong iter= arg_count > 2 ? args[2]->val_int() : 1000; + if (iter <= 0) + { + if (!args[2]->null_value) + invalid_argument_error(func_name(), + ErrConvInteger({iter, args[2]->unsigned_flag}).ptr()); + } + else + ok= PKCS5_PBKDF2_HMAC(key->ptr(), key->length(), + (const uchar*)salt->ptr(), salt->length(), (int)iter, + EVP_sha512(), (int)klen, (uchar*)buf->ptr()); + } + + if (ok) + { + null_value= 0; + return buf; + } + +ret_null: + null_value=1; + return 0; +} bool Item_func_to_base64::fix_length_and_dec(THD *thd) { diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index fd41ea100e7..fdae00ae56a 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -133,6 +133,8 @@ public: :Item_str_func(thd, a, b, c) { } Item_str_binary_checksum_func(THD *thd, Item *a, Item *b, Item *c, Item *d) :Item_str_func(thd, a, b, c, d) { } + Item_str_binary_checksum_func(THD *thd, Item *a, Item *b, Item *c, Item *d, Item *e) + :Item_str_func(thd, a, b, c, d, e) { } bool eq(const Item *item, bool binary_cmp) const { /* @@ -295,6 +297,35 @@ public: { return get_item_copy(thd, this); } }; +class Item_func_kdf :public Item_str_binary_checksum_func +{ + uint key_length; +public: + Item_func_kdf(THD *thd, Item *a, Item *b) + : Item_str_binary_checksum_func(thd, a, b) {} + Item_func_kdf(THD *thd, Item *a, Item *b, Item *c) + : Item_str_binary_checksum_func(thd, a, b, c) {} + Item_func_kdf(THD *thd, Item *a, Item *b, Item *c, Item *d) + : Item_str_binary_checksum_func(thd, a, b, c, d) {} + Item_func_kdf(THD *thd, Item *a, Item *b, Item *c, Item *d, Item *e) + : Item_str_binary_checksum_func(thd, a, b, c, d, e) {} + bool fix_length_and_dec(THD *thd) override; + String *val_str(String *) override; + bool check_vcol_func_processor(void *arg) override + { + if (arg_count > 4) + return FALSE; + return mark_unsupported_function(func_name(), "()", arg, VCOL_SESSION_FUNC); + } + LEX_CSTRING func_name_cstring() const override + { + static LEX_CSTRING name= {STRING_WITH_LEN("kdf") }; + return name; + } + Item *get_copy(THD *thd) override + { return get_item_copy(thd, this); } +}; + class Item_func_natural_sort_key : public Item_str_func { public: