1 /* 2 * QEMU Crypto random number provider 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 23 #include "crypto/random.h" 24 #include "qapi/error.h" 25 26 #ifdef _WIN32 27 #include <wincrypt.h> 28 static HCRYPTPROV hCryptProv; 29 #else 30 # ifdef CONFIG_GETRANDOM 31 # include <sys/random.h> 32 # endif 33 /* This is -1 for getrandom(), or a file handle for /dev/{u,}random. */ 34 static int fd; 35 #endif 36 37 int qcrypto_random_init(Error **errp) 38 { 39 #ifdef _WIN32 40 if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 41 CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) { 42 error_setg_win32(errp, GetLastError(), 43 "Unable to create cryptographic provider"); 44 return -1; 45 } 46 #else 47 # ifdef CONFIG_GETRANDOM 48 if (getrandom(NULL, 0, 0) == 0) { 49 /* Use getrandom() */ 50 fd = -1; 51 return 0; 52 } 53 /* Fall through to /dev/urandom case. */ 54 # endif 55 fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); 56 if (fd == -1 && errno == ENOENT) { 57 fd = open("/dev/random", O_RDONLY | O_CLOEXEC); 58 } 59 if (fd < 0) { 60 error_setg_errno(errp, errno, "No /dev/urandom or /dev/random"); 61 return -1; 62 } 63 #endif 64 return 0; 65 } 66 67 int qcrypto_random_bytes(void *buf, 68 size_t buflen, 69 Error **errp) 70 { 71 #ifdef _WIN32 72 if (!CryptGenRandom(hCryptProv, buflen, buf)) { 73 error_setg_win32(errp, GetLastError(), 74 "Unable to read random bytes"); 75 return -1; 76 } 77 #else 78 # ifdef CONFIG_GETRANDOM 79 if (likely(fd < 0)) { 80 while (1) { 81 ssize_t got = getrandom(buf, buflen, 0); 82 if (likely(got == buflen)) { 83 return 0; 84 } 85 if (got >= 0) { 86 buflen -= got; 87 buf += got; 88 } else if (errno != EINTR) { 89 error_setg_errno(errp, errno, "getrandom"); 90 return -1; 91 } 92 } 93 } 94 /* Fall through to /dev/urandom case. */ 95 # endif 96 while (1) { 97 ssize_t got = read(fd, buf, buflen); 98 if (likely(got == buflen)) { 99 return 0; 100 } 101 if (got > 0) { 102 buflen -= got; 103 buf += got; 104 } else if (got == 0) { 105 error_setg(errp, "Unexpected EOF reading random bytes"); 106 return -1; 107 } else if (errno != EINTR) { 108 error_setg_errno(errp, errno, "Unable to read random bytes"); 109 return -1; 110 } 111 } 112 #endif 113 return 0; 114 } 115