RdRand.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /** @file
  2. Support routines for RDRAND instruction access.
  3. Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
  4. (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include <Library/RngLib.h>
  8. #include "RdRand.h"
  9. #include "AesCore.h"
  10. /**
  11. Calls RDRAND to fill a buffer of arbitrary size with random bytes.
  12. @param[in] Length Size of the buffer, in bytes, to fill with.
  13. @param[out] RandBuffer Pointer to the buffer to store the random result.
  14. @retval EFI_SUCCESS Random bytes generation succeeded.
  15. @retval EFI_NOT_READY Failed to request random bytes.
  16. **/
  17. EFI_STATUS
  18. EFIAPI
  19. RdRandGetBytes (
  20. IN UINTN Length,
  21. OUT UINT8 *RandBuffer
  22. )
  23. {
  24. BOOLEAN IsRandom;
  25. UINT64 TempRand[2];
  26. while (Length > 0) {
  27. IsRandom = GetRandomNumber128 (TempRand);
  28. if (!IsRandom) {
  29. return EFI_NOT_READY;
  30. }
  31. if (Length >= sizeof (TempRand)) {
  32. WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[0]);
  33. RandBuffer += sizeof (UINT64);
  34. WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[1]);
  35. RandBuffer += sizeof (UINT64);
  36. Length -= sizeof (TempRand);
  37. } else {
  38. CopyMem (RandBuffer, TempRand, Length);
  39. Length = 0;
  40. }
  41. }
  42. return EFI_SUCCESS;
  43. }
  44. /**
  45. Creates a 128bit random value that is fully forward and backward prediction resistant,
  46. suitable for seeding a NIST SP800-90 Compliant, FIPS 1402-2 certifiable SW DRBG.
  47. This function takes multiple random numbers through RDRAND without intervening
  48. delays to ensure reseeding and performs AES-CBC-MAC over the data to compute the
  49. seed value.
  50. @param[out] SeedBuffer Pointer to a 128bit buffer to store the random seed.
  51. @retval EFI_SUCCESS Random seed generation succeeded.
  52. @retval EFI_NOT_READY Failed to request random bytes.
  53. **/
  54. EFI_STATUS
  55. EFIAPI
  56. RdRandGetSeed128 (
  57. OUT UINT8 *SeedBuffer
  58. )
  59. {
  60. EFI_STATUS Status;
  61. UINT8 RandByte[16];
  62. UINT8 Key[16];
  63. UINT8 Ffv[16];
  64. UINT8 Xored[16];
  65. UINT32 Index;
  66. UINT32 Index2;
  67. //
  68. // Chose an arbitrary key and zero the feed_forward_value (FFV)
  69. //
  70. for (Index = 0; Index < 16; Index++) {
  71. Key[Index] = (UINT8) Index;
  72. Ffv[Index] = 0;
  73. }
  74. //
  75. // Perform CBC_MAC over 32 * 128 bit values, with 10us gaps between 128 bit value
  76. // The 10us gaps will ensure multiple reseeds within the HW RNG with a large design margin.
  77. //
  78. for (Index = 0; Index < 32; Index++) {
  79. MicroSecondDelay (10);
  80. Status = RdRandGetBytes (16, RandByte);
  81. if (EFI_ERROR (Status)) {
  82. return Status;
  83. }
  84. //
  85. // Perform XOR operations on two 128-bit value.
  86. //
  87. for (Index2 = 0; Index2 < 16; Index2++) {
  88. Xored[Index2] = RandByte[Index2] ^ Ffv[Index2];
  89. }
  90. AesEncrypt (Key, Xored, Ffv);
  91. }
  92. for (Index = 0; Index < 16; Index++) {
  93. SeedBuffer[Index] = Ffv[Index];
  94. }
  95. return EFI_SUCCESS;
  96. }
  97. /**
  98. Generate high-quality entropy source through RDRAND.
  99. @param[in] Length Size of the buffer, in bytes, to fill with.
  100. @param[out] Entropy Pointer to the buffer to store the entropy data.
  101. @retval EFI_SUCCESS Entropy generation succeeded.
  102. @retval EFI_NOT_READY Failed to request random data.
  103. **/
  104. EFI_STATUS
  105. EFIAPI
  106. RdRandGenerateEntropy (
  107. IN UINTN Length,
  108. OUT UINT8 *Entropy
  109. )
  110. {
  111. EFI_STATUS Status;
  112. UINTN BlockCount;
  113. UINT8 Seed[16];
  114. UINT8 *Ptr;
  115. Status = EFI_NOT_READY;
  116. BlockCount = Length / 16;
  117. Ptr = (UINT8 *)Entropy;
  118. //
  119. // Generate high-quality seed for DRBG Entropy
  120. //
  121. while (BlockCount > 0) {
  122. Status = RdRandGetSeed128 (Seed);
  123. if (EFI_ERROR (Status)) {
  124. return Status;
  125. }
  126. CopyMem (Ptr, Seed, 16);
  127. BlockCount--;
  128. Ptr = Ptr + 16;
  129. }
  130. //
  131. // Populate the remained data as request.
  132. //
  133. Status = RdRandGetSeed128 (Seed);
  134. if (EFI_ERROR (Status)) {
  135. return Status;
  136. }
  137. CopyMem (Ptr, Seed, (Length % 16));
  138. return Status;
  139. }