pbkdf.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
  3. *
  4. * Copyright (c) 2015-2016 Red Hat, Inc.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. #include "qemu/osdep.h"
  21. #include "qapi/error.h"
  22. #include "crypto/pbkdf.h"
  23. #ifndef _WIN32
  24. #include <sys/resource.h>
  25. #endif
  26. #ifdef CONFIG_DARWIN
  27. #include <mach/mach_init.h>
  28. #include <mach/thread_act.h>
  29. #include <mach/mach_port.h>
  30. #endif
  31. static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
  32. Error **errp)
  33. {
  34. #ifdef _WIN32
  35. FILETIME creation_time, exit_time, kernel_time, user_time;
  36. ULARGE_INTEGER thread_time;
  37. if (!GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time,
  38. &kernel_time, &user_time)) {
  39. error_setg(errp, "Unable to get thread CPU usage");
  40. return -1;
  41. }
  42. thread_time.LowPart = user_time.dwLowDateTime;
  43. thread_time.HighPart = user_time.dwHighDateTime;
  44. /* QuadPart is units of 100ns and we want ms as unit */
  45. *val_ms = thread_time.QuadPart / 10000ll;
  46. return 0;
  47. #elif defined(CONFIG_DARWIN)
  48. mach_port_t thread;
  49. kern_return_t kr;
  50. mach_msg_type_number_t count;
  51. thread_basic_info_data_t info;
  52. thread = mach_thread_self();
  53. count = THREAD_BASIC_INFO_COUNT;
  54. kr = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count);
  55. mach_port_deallocate(mach_task_self(), thread);
  56. if (kr != KERN_SUCCESS || (info.flags & TH_FLAGS_IDLE) != 0) {
  57. error_setg_errno(errp, errno, "Unable to get thread CPU usage");
  58. return -1;
  59. }
  60. *val_ms = ((info.user_time.seconds * 1000ll) +
  61. (info.user_time.microseconds / 1000));
  62. return 0;
  63. #elif defined(RUSAGE_THREAD)
  64. struct rusage ru;
  65. if (getrusage(RUSAGE_THREAD, &ru) < 0) {
  66. error_setg_errno(errp, errno, "Unable to get thread CPU usage");
  67. return -1;
  68. }
  69. *val_ms = ((ru.ru_utime.tv_sec * 1000ll) +
  70. (ru.ru_utime.tv_usec / 1000));
  71. return 0;
  72. #else
  73. *val_ms = 0;
  74. error_setg(errp, "Unable to calculate thread CPU usage on this platform");
  75. return -1;
  76. #endif
  77. }
  78. uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
  79. const uint8_t *key, size_t nkey,
  80. const uint8_t *salt, size_t nsalt,
  81. size_t nout,
  82. Error **errp)
  83. {
  84. uint64_t ret = -1;
  85. g_autofree uint8_t *out = g_new(uint8_t, nout);
  86. uint64_t iterations = (1 << 15);
  87. unsigned long long delta_ms, start_ms, end_ms;
  88. while (1) {
  89. if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
  90. goto cleanup;
  91. }
  92. if (qcrypto_pbkdf2(hash,
  93. key, nkey,
  94. salt, nsalt,
  95. iterations,
  96. out, nout,
  97. errp) < 0) {
  98. goto cleanup;
  99. }
  100. if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
  101. goto cleanup;
  102. }
  103. delta_ms = end_ms - start_ms;
  104. if (delta_ms > 500) {
  105. break;
  106. } else if (delta_ms < 100) {
  107. iterations = iterations * 10;
  108. } else {
  109. iterations = (iterations * 1000 / delta_ms);
  110. }
  111. }
  112. iterations = iterations * 1000 / delta_ms;
  113. ret = iterations;
  114. cleanup:
  115. memset(out, 0, nout);
  116. return ret;
  117. }