137788f25SDaniel P. Berrange /*
237788f25SDaniel P. Berrange * QEMU Crypto PBKDF support (Password-Based Key Derivation Function)
337788f25SDaniel P. Berrange *
437788f25SDaniel P. Berrange * Copyright (c) 2015-2016 Red Hat, Inc.
537788f25SDaniel P. Berrange *
637788f25SDaniel P. Berrange * This library is free software; you can redistribute it and/or
737788f25SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public
837788f25SDaniel P. Berrange * License as published by the Free Software Foundation; either
9b7cbb874SThomas Huth * version 2.1 of the License, or (at your option) any later version.
1037788f25SDaniel P. Berrange *
1137788f25SDaniel P. Berrange * This library is distributed in the hope that it will be useful,
1237788f25SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
1337788f25SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1437788f25SDaniel P. Berrange * Lesser General Public License for more details.
1537788f25SDaniel P. Berrange *
1637788f25SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public
1737788f25SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1837788f25SDaniel P. Berrange *
1937788f25SDaniel P. Berrange */
2037788f25SDaniel P. Berrange
2137788f25SDaniel P. Berrange #include "qemu/osdep.h"
22c72cab5aSTiago Pasqualini #include "qemu/thread.h"
23da34e65cSMarkus Armbruster #include "qapi/error.h"
2437788f25SDaniel P. Berrange #include "crypto/pbkdf.h"
2537788f25SDaniel P. Berrange #ifndef _WIN32
2637788f25SDaniel P. Berrange #include <sys/resource.h>
2737788f25SDaniel P. Berrange #endif
28bf98afc7SJungmin Park #ifdef CONFIG_DARWIN
29bf98afc7SJungmin Park #include <mach/mach_init.h>
30bf98afc7SJungmin Park #include <mach/thread_act.h>
31bf98afc7SJungmin Park #include <mach/mach_port.h>
32bf98afc7SJungmin Park #endif
3337788f25SDaniel P. Berrange
3437788f25SDaniel P. Berrange
qcrypto_pbkdf2_get_thread_cpu(unsigned long long * val_ms,Error ** errp)3537788f25SDaniel P. Berrange static int qcrypto_pbkdf2_get_thread_cpu(unsigned long long *val_ms,
3637788f25SDaniel P. Berrange Error **errp)
3737788f25SDaniel P. Berrange {
3837788f25SDaniel P. Berrange #ifdef _WIN32
3937788f25SDaniel P. Berrange FILETIME creation_time, exit_time, kernel_time, user_time;
4037788f25SDaniel P. Berrange ULARGE_INTEGER thread_time;
4137788f25SDaniel P. Berrange
4237788f25SDaniel P. Berrange if (!GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time,
4337788f25SDaniel P. Berrange &kernel_time, &user_time)) {
4437788f25SDaniel P. Berrange error_setg(errp, "Unable to get thread CPU usage");
4537788f25SDaniel P. Berrange return -1;
4637788f25SDaniel P. Berrange }
4737788f25SDaniel P. Berrange
4837788f25SDaniel P. Berrange thread_time.LowPart = user_time.dwLowDateTime;
4937788f25SDaniel P. Berrange thread_time.HighPart = user_time.dwHighDateTime;
5037788f25SDaniel P. Berrange
5137788f25SDaniel P. Berrange /* QuadPart is units of 100ns and we want ms as unit */
5237788f25SDaniel P. Berrange *val_ms = thread_time.QuadPart / 10000ll;
5337788f25SDaniel P. Berrange return 0;
54bf98afc7SJungmin Park #elif defined(CONFIG_DARWIN)
55bf98afc7SJungmin Park mach_port_t thread;
56bf98afc7SJungmin Park kern_return_t kr;
57bf98afc7SJungmin Park mach_msg_type_number_t count;
58bf98afc7SJungmin Park thread_basic_info_data_t info;
59bf98afc7SJungmin Park
60bf98afc7SJungmin Park thread = mach_thread_self();
61bf98afc7SJungmin Park count = THREAD_BASIC_INFO_COUNT;
62bf98afc7SJungmin Park kr = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &count);
63bf98afc7SJungmin Park mach_port_deallocate(mach_task_self(), thread);
64bf98afc7SJungmin Park if (kr != KERN_SUCCESS || (info.flags & TH_FLAGS_IDLE) != 0) {
65bf98afc7SJungmin Park error_setg_errno(errp, errno, "Unable to get thread CPU usage");
66bf98afc7SJungmin Park return -1;
67bf98afc7SJungmin Park }
68bf98afc7SJungmin Park
69bf98afc7SJungmin Park *val_ms = ((info.user_time.seconds * 1000ll) +
70bf98afc7SJungmin Park (info.user_time.microseconds / 1000));
71bf98afc7SJungmin Park return 0;
7237788f25SDaniel P. Berrange #elif defined(RUSAGE_THREAD)
7337788f25SDaniel P. Berrange struct rusage ru;
7437788f25SDaniel P. Berrange if (getrusage(RUSAGE_THREAD, &ru) < 0) {
7537788f25SDaniel P. Berrange error_setg_errno(errp, errno, "Unable to get thread CPU usage");
7637788f25SDaniel P. Berrange return -1;
7737788f25SDaniel P. Berrange }
7837788f25SDaniel P. Berrange
7937788f25SDaniel P. Berrange *val_ms = ((ru.ru_utime.tv_sec * 1000ll) +
8037788f25SDaniel P. Berrange (ru.ru_utime.tv_usec / 1000));
8137788f25SDaniel P. Berrange return 0;
8237788f25SDaniel P. Berrange #else
8337788f25SDaniel P. Berrange *val_ms = 0;
8437788f25SDaniel P. Berrange error_setg(errp, "Unable to calculate thread CPU usage on this platform");
8537788f25SDaniel P. Berrange return -1;
8637788f25SDaniel P. Berrange #endif
8737788f25SDaniel P. Berrange }
8837788f25SDaniel P. Berrange
89c72cab5aSTiago Pasqualini typedef struct CountItersData {
90ef834aa2SMarkus Armbruster QCryptoHashAlgo hash;
91c72cab5aSTiago Pasqualini const uint8_t *key;
92c72cab5aSTiago Pasqualini size_t nkey;
93c72cab5aSTiago Pasqualini const uint8_t *salt;
94c72cab5aSTiago Pasqualini size_t nsalt;
95c72cab5aSTiago Pasqualini size_t nout;
96c72cab5aSTiago Pasqualini uint64_t iterations;
97c72cab5aSTiago Pasqualini Error **errp;
98c72cab5aSTiago Pasqualini } CountItersData;
99c72cab5aSTiago Pasqualini
threaded_qcrypto_pbkdf2_count_iters(void * data)100c72cab5aSTiago Pasqualini static void *threaded_qcrypto_pbkdf2_count_iters(void *data)
10137788f25SDaniel P. Berrange {
102c72cab5aSTiago Pasqualini CountItersData *iters_data = (CountItersData *) data;
103ef834aa2SMarkus Armbruster QCryptoHashAlgo hash = iters_data->hash;
104c72cab5aSTiago Pasqualini const uint8_t *key = iters_data->key;
105c72cab5aSTiago Pasqualini size_t nkey = iters_data->nkey;
106c72cab5aSTiago Pasqualini const uint8_t *salt = iters_data->salt;
107c72cab5aSTiago Pasqualini size_t nsalt = iters_data->nsalt;
108c72cab5aSTiago Pasqualini size_t nout = iters_data->nout;
109c72cab5aSTiago Pasqualini Error **errp = iters_data->errp;
110*dcb80cd9SDaniel P. Berrangé size_t scaled = 0;
1118813800bSDaniel P. Berrange uint64_t ret = -1;
11257b9f113SDaniel P. Berrangé g_autofree uint8_t *out = g_new(uint8_t, nout);
11359b060beSDaniel P. Berrange uint64_t iterations = (1 << 15);
11437788f25SDaniel P. Berrange unsigned long long delta_ms, start_ms, end_ms;
11537788f25SDaniel P. Berrange
11637788f25SDaniel P. Berrange while (1) {
11737788f25SDaniel P. Berrange if (qcrypto_pbkdf2_get_thread_cpu(&start_ms, errp) < 0) {
1188813800bSDaniel P. Berrange goto cleanup;
11937788f25SDaniel P. Berrange }
12037788f25SDaniel P. Berrange if (qcrypto_pbkdf2(hash,
12137788f25SDaniel P. Berrange key, nkey,
12237788f25SDaniel P. Berrange salt, nsalt,
12337788f25SDaniel P. Berrange iterations,
124e74aabcfSDaniel P. Berrange out, nout,
12537788f25SDaniel P. Berrange errp) < 0) {
1268813800bSDaniel P. Berrange goto cleanup;
12737788f25SDaniel P. Berrange }
12837788f25SDaniel P. Berrange if (qcrypto_pbkdf2_get_thread_cpu(&end_ms, errp) < 0) {
1298813800bSDaniel P. Berrange goto cleanup;
13037788f25SDaniel P. Berrange }
13137788f25SDaniel P. Berrange
13237788f25SDaniel P. Berrange delta_ms = end_ms - start_ms;
13337788f25SDaniel P. Berrange
134*dcb80cd9SDaniel P. Berrangé /*
135*dcb80cd9SDaniel P. Berrangé * For very small 'iterations' values, CPU (or crypto
136*dcb80cd9SDaniel P. Berrangé * accelerator) might be fast enough that the scheduler
137*dcb80cd9SDaniel P. Berrangé * hasn't incremented getrusage() data, or incremented
138*dcb80cd9SDaniel P. Berrangé * it by a very small amount, resulting in delta_ms == 0.
139*dcb80cd9SDaniel P. Berrangé * Once we've scaled 'iterations' x10, 5 times, we really
140*dcb80cd9SDaniel P. Berrangé * should be seeing delta_ms != 0, so sanity check at
141*dcb80cd9SDaniel P. Berrangé * that point.
142*dcb80cd9SDaniel P. Berrangé */
143*dcb80cd9SDaniel P. Berrangé if (scaled > 5 &&
144*dcb80cd9SDaniel P. Berrangé delta_ms == 0) { /* sanity check */
145c72cab5aSTiago Pasqualini error_setg(errp, "Unable to get accurate CPU usage");
146c72cab5aSTiago Pasqualini goto cleanup;
147c72cab5aSTiago Pasqualini } else if (delta_ms > 500) {
14837788f25SDaniel P. Berrange break;
14937788f25SDaniel P. Berrange } else if (delta_ms < 100) {
15037788f25SDaniel P. Berrange iterations = iterations * 10;
15137788f25SDaniel P. Berrange } else {
15237788f25SDaniel P. Berrange iterations = (iterations * 1000 / delta_ms);
15337788f25SDaniel P. Berrange }
154*dcb80cd9SDaniel P. Berrangé scaled++;
15537788f25SDaniel P. Berrange }
15637788f25SDaniel P. Berrange
15737788f25SDaniel P. Berrange iterations = iterations * 1000 / delta_ms;
15837788f25SDaniel P. Berrange
1598813800bSDaniel P. Berrange ret = iterations;
1608813800bSDaniel P. Berrange
1618813800bSDaniel P. Berrange cleanup:
162e74aabcfSDaniel P. Berrange memset(out, 0, nout);
163c72cab5aSTiago Pasqualini iters_data->iterations = ret;
164c72cab5aSTiago Pasqualini return NULL;
165c72cab5aSTiago Pasqualini }
166c72cab5aSTiago Pasqualini
qcrypto_pbkdf2_count_iters(QCryptoHashAlgo hash,const uint8_t * key,size_t nkey,const uint8_t * salt,size_t nsalt,size_t nout,Error ** errp)167ef834aa2SMarkus Armbruster uint64_t qcrypto_pbkdf2_count_iters(QCryptoHashAlgo hash,
168c72cab5aSTiago Pasqualini const uint8_t *key, size_t nkey,
169c72cab5aSTiago Pasqualini const uint8_t *salt, size_t nsalt,
170c72cab5aSTiago Pasqualini size_t nout,
171c72cab5aSTiago Pasqualini Error **errp)
172c72cab5aSTiago Pasqualini {
173c72cab5aSTiago Pasqualini CountItersData data = {
174c72cab5aSTiago Pasqualini hash, key, nkey, salt, nsalt, nout, 0, errp
175c72cab5aSTiago Pasqualini };
176c72cab5aSTiago Pasqualini QemuThread thread;
177c72cab5aSTiago Pasqualini
178c72cab5aSTiago Pasqualini qemu_thread_create(&thread, "pbkdf2", threaded_qcrypto_pbkdf2_count_iters,
179c72cab5aSTiago Pasqualini &data, QEMU_THREAD_JOINABLE);
180c72cab5aSTiago Pasqualini qemu_thread_join(&thread);
181c72cab5aSTiago Pasqualini
182c72cab5aSTiago Pasqualini return data.iterations;
18337788f25SDaniel P. Berrange }
184