pbkdf.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  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. static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
  27. Error **errp)
  28. {
  29. #ifdef _WIN32
  30. FILETIME creation_time, exit_time, kernel_time, user_time;
  31. ULARGE_INTEGER thread_time;
  32. if (!GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time,
  33. &kernel_time, &user_time)) {
  34. error_setg(errp, "Unable to get thread CPU usage");
  35. return -1;
  36. }
  37. thread_time.LowPart = user_time.dwLowDateTime;
  38. thread_time.HighPart = user_time.dwHighDateTime;
  39. /* QuadPart is units of 100ns and we want ms as unit */
  40. *val_ms = thread_time.QuadPart / 10000ll;
  41. return 0;
  42. #elif defined(RUSAGE_THREAD)
  43. struct rusage ru;
  44. if (getrusage(RUSAGE_THREAD, &ru) < 0) {
  45. error_setg_errno(errp, errno, "Unable to get thread CPU usage");
  46. return -1;
  47. }
  48. *val_ms = ((ru.ru_utime.tv_sec * 1000ll) +
  49. (ru.ru_utime.tv_usec / 1000));
  50. return 0;
  51. #else
  52. *val_ms = 0;
  53. error_setg(errp, "Unable to calculate thread CPU usage on this platform");
  54. return -1;
  55. #endif
  56. }
  57. uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash,
  58. const uint8_t *key, size_t nkey,
  59. const uint8_t *salt, size_t nsalt,
  60. size_t nout,
  61. Error **errp)
  62. {
  63. uint64_t ret = -1;
  64. g_autofree uint8_t *out = g_new(uint8_t, nout);
  65. uint64_t iterations = (1 << 15);
  66. unsigned long long delta_ms, start_ms, end_ms;
  67. while (1) {
  68. if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
  69. goto cleanup;
  70. }
  71. if (qcrypto_pbkdf2(hash,
  72. key, nkey,
  73. salt, nsalt,
  74. iterations,
  75. out, nout,
  76. errp) < 0) {
  77. goto cleanup;
  78. }
  79. if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
  80. goto cleanup;
  81. }
  82. delta_ms = end_ms - start_ms;
  83. if (delta_ms > 500) {
  84. break;
  85. } else if (delta_ms < 100) {
  86. iterations = iterations * 10;
  87. } else {
  88. iterations = (iterations * 1000 / delta_ms);
  89. }
  90. }
  91. iterations = iterations * 1000 / delta_ms;
  92. ret = iterations;
  93. cleanup:
  94. memset(out, 0, nout);
  95. return ret;
  96. }