xref: /openbmc/qemu/crypto/pbkdf.c (revision dcb80cd90832b11133f3c73706c63698f3b6e714)
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