You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

random-platform.c 3.1KB

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