random.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright (c) 2016-2019 DeNA Co., Ltd., Kazuho Oku, Christian Huitema
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to
  6. * deal in the Software without restriction, including without limitation the
  7. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. * sell copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. * IN THE SOFTWARE.
  21. */
  22. #ifndef _XOPEN_SOURCE
  23. #define _XOPEN_SOURCE 700 /* required for glibc to use getaddrinfo, etc. */
  24. #endif
  25. #include <errno.h>
  26. #include <fcntl.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #ifdef _WINDOWS
  30. #include "wincompat.h"
  31. #else
  32. #include <unistd.h>
  33. #endif
  34. #include "drbg.h"
  35. #include "picotls.h"
  36. #include "picotls/minicrypto.h"
  37. #include <stdio.h>
  38. #ifdef _WINDOWS
  39. #ifdef _WINDOWS_XP
  40. /* The modern BCrypt API is only available on Windows Vista and later versions.
  41. * If compiling on Windows XP, we need to use the olded "wincrypt" API */
  42. #include <wincrypt.h>
  43. static void read_entropy(uint8_t *entropy, size_t size)
  44. {
  45. HCRYPTPROV hCryptProv = 0;
  46. BOOL ret = FALSE;
  47. if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
  48. ret = CryptGenRandom(hCryptProv, (DWORD)size, entropy);
  49. (void)CryptReleaseContext(hCryptProv, 0);
  50. }
  51. if (ret == FALSE) {
  52. perror("ptls_minicrypto_random_bytes: could not use CryptGenRandom");
  53. abort();
  54. }
  55. }
  56. #else
  57. /* The old "Wincrypt" API requires access to default security containers.
  58. * This can cause access control errors on some systems. We prefer
  59. * to use the modern BCrypt API when available */
  60. #include <bcrypt.h>
  61. static void read_entropy(uint8_t *entropy, size_t size)
  62. {
  63. NTSTATUS nts = 0;
  64. BCRYPT_ALG_HANDLE hAlgorithm = 0;
  65. nts = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RNG_ALGORITHM, NULL, 0);
  66. if (BCRYPT_SUCCESS(nts)) {
  67. nts = BCryptGenRandom(hAlgorithm, (PUCHAR)entropy, (ULONG)size, 0);
  68. (void)BCryptCloseAlgorithmProvider(hAlgorithm, 0);
  69. }
  70. if (!BCRYPT_SUCCESS(nts)) {
  71. perror("ptls_minicrypto_random_bytes: could not open BCrypt RNG Algorithm");
  72. abort();
  73. }
  74. }
  75. #endif
  76. #else
  77. static void read_entropy(uint8_t *entropy, size_t size)
  78. {
  79. int fd;
  80. if ((fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) == -1) {
  81. if ((fd = open("/dev/random", O_RDONLY | O_CLOEXEC)) == -1) {
  82. perror("ptls_minicrypto_random_bytes: could not open neither /dev/random or /dev/urandom");
  83. abort();
  84. }
  85. }
  86. while (size != 0) {
  87. ssize_t rret;
  88. while ((rret = read(fd, entropy, size)) == -1 && errno == EINTR)
  89. ;
  90. if (rret < 0) {
  91. perror("ptls_minicrypto_random_bytes");
  92. abort();
  93. }
  94. entropy += rret;
  95. size -= rret;
  96. }
  97. close(fd);
  98. }
  99. #endif
  100. void ptls_minicrypto_random_bytes(void *buf, size_t len)
  101. {
  102. static PTLS_THREADLOCAL cf_hash_drbg_sha256 ctx;
  103. if (cf_hash_drbg_sha256_needs_reseed(&ctx)) {
  104. uint8_t entropy[256];
  105. read_entropy(entropy, sizeof(entropy));
  106. cf_hash_drbg_sha256_init(&ctx, entropy, sizeof(entropy) / 2, entropy + sizeof(entropy) / 2, sizeof(entropy) / 2, "ptls", 4);
  107. }
  108. cf_hash_drbg_sha256_gen(&ctx, buf, len);
  109. }