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 21 #include "qemu/osdep.h" 22 #include "qapi/error.h" 23 #include "crypto/pbkdf.h" 24 #ifndef _WIN32 25 #include <sys/resource.h> 26 #endif 27 #ifdef CONFIG_DARWIN 28 #include <mach/mach_init.h> 29 #include <mach/thread_act.h> 30 #include <mach/mach_port.h> 31 #endif 32 33 34 static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms, 35 Error **errp) 36 { 37 #ifdef _WIN32 38 FILETIME creation_time, exit_time, kernel_time, user_time; 39 ULARGE_INTEGER thread_time; 40 41 if (!GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time, 42 &kernel_time, &user_time)) { 43 error_setg(errp, "Unable to get thread CPU usage"); 44 return -1; 45 } 46 47 thread_time.LowPart = user_time.dwLowDateTime; 48 thread_time.HighPart = user_time.dwHighDateTime; 49 50 /* QuadPart is units of 100ns and we want ms as unit */ 51 *val_ms = thread_time.QuadPart / 10000ll; 52 return 0; 53 #elif defined(CONFIG_DARWIN) 54 mach_port_t thread; 55 kern_return_t kr; 56 mach_msg_type_number_t count; 57 thread_basic_info_data_t info; 58 59 thread = mach_thread_self(); 60 count = THREAD_BASIC_INFO_COUNT; 61 kr = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count); 62 mach_port_deallocate(mach_task_self(), thread); 63 if (kr != KERN_SUCCESS || (info.flags & TH_FLAGS_IDLE) != 0) { 64 error_setg_errno(errp, errno, "Unable to get thread CPU usage"); 65 return -1; 66 } 67 68 *val_ms = ((info.user_time.seconds * 1000ll) + 69 (info.user_time.microseconds / 1000)); 70 return 0; 71 #elif defined(RUSAGE_THREAD) 72 struct rusage ru; 73 if (getrusage(RUSAGE_THREAD, &ru) < 0) { 74 error_setg_errno(errp, errno, "Unable to get thread CPU usage"); 75 return -1; 76 } 77 78 *val_ms = ((ru.ru_utime.tv_sec * 1000ll) + 79 (ru.ru_utime.tv_usec / 1000)); 80 return 0; 81 #else 82 *val_ms = 0; 83 error_setg(errp, "Unable to calculate thread CPU usage on this platform"); 84 return -1; 85 #endif 86 } 87 88 uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgorithm hash, 89 const uint8_t *key, size_t nkey, 90 const uint8_t *salt, size_t nsalt, 91 size_t nout, 92 Error **errp) 93 { 94 uint64_t ret = -1; 95 g_autofree uint8_t *out = g_new(uint8_t, nout); 96 uint64_t iterations = (1 << 15); 97 unsigned long long delta_ms, start_ms, end_ms; 98 99 while (1) { 100 if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) { 101 goto cleanup; 102 } 103 if (qcrypto_pbkdf2(hash, 104 key, nkey, 105 salt, nsalt, 106 iterations, 107 out, nout, 108 errp) < 0) { 109 goto cleanup; 110 } 111 if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) { 112 goto cleanup; 113 } 114 115 delta_ms = end_ms - start_ms; 116 117 if (delta_ms > 500) { 118 break; 119 } else if (delta_ms < 100) { 120 iterations = iterations * 10; 121 } else { 122 iterations = (iterations * 1000 / delta_ms); 123 } 124 } 125 126 iterations = iterations * 1000 / delta_ms; 127 128 ret = iterations; 129 130 cleanup: 131 memset(out, 0, nout); 132 return ret; 133 } 134