Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

186 lignes
4.4 KiB

  1. /* Jitter RNG: GCD health test
  2. *
  3. * Copyright (C) 2021 - 2022, Joshua E. Hill <josh@keypair.us>
  4. * Copyright (C) 2021 - 2022, Stephan Mueller <smueller@chronox.de>
  5. *
  6. * License: see LICENSE file in root directory
  7. *
  8. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  9. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  10. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
  11. * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
  12. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  13. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  14. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  15. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  16. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  17. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  18. * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
  19. * DAMAGE.
  20. */
  21. #include "jitterentropy.h"
  22. #include "jitterentropy-gcd.h"
  23. /* The common divisor for all timestamp deltas */
  24. static uint64_t jent_common_timer_gcd = 0;
  25. static inline int jent_gcd_tested(void)
  26. {
  27. return (jent_common_timer_gcd != 0);
  28. }
  29. /* A straight forward implementation of the Euclidean algorithm for GCD. */
  30. static inline uint64_t jent_gcd64(uint64_t a, uint64_t b)
  31. {
  32. /* Make a greater a than or equal b. */
  33. if (a < b) {
  34. uint64_t c = a;
  35. a = b;
  36. b = c;
  37. }
  38. /* Now perform the standard inner-loop for this algorithm.*/
  39. while (b != 0) {
  40. uint64_t r;
  41. r = a % b;
  42. a = b;
  43. b = r;
  44. }
  45. return a;
  46. }
  47. static int jent_gcd_analyze_internal(uint64_t *delta_history, size_t nelem,
  48. uint64_t *running_gcd_out,
  49. uint64_t *delta_sum_out)
  50. {
  51. uint64_t running_gcd, delta_sum = 0;
  52. size_t i;
  53. if (!delta_history)
  54. return -EAGAIN;
  55. running_gcd = delta_history[0];
  56. /* Now perform the analysis on the accumulated delta data. */
  57. for (i = 1; i < nelem; i++) {
  58. /*
  59. * ensure that we have a varying delta timer which is necessary
  60. * for the calculation of entropy -- perform this check
  61. * only after the first loop is executed as we need to prime
  62. * the old_data value
  63. */
  64. if (delta_history[i] >= delta_history[i - 1])
  65. delta_sum += delta_history[i] - delta_history[i - 1];
  66. else
  67. delta_sum += delta_history[i - 1] - delta_history[i];
  68. /*
  69. * This calculates the gcd of all the delta values. that is
  70. * gcd(delta_1, delta_2, ..., delta_nelem)
  71. * Some timers increment by a fixed (non-1) amount each step.
  72. * This code checks for such increments, and allows the library
  73. * to output the number of such changes have occurred.
  74. */
  75. running_gcd = jent_gcd64(delta_history[i], running_gcd);
  76. }
  77. *running_gcd_out = running_gcd;
  78. *delta_sum_out = delta_sum;
  79. return 0;
  80. }
  81. int jent_gcd_analyze(uint64_t *delta_history, size_t nelem)
  82. {
  83. uint64_t running_gcd, delta_sum;
  84. int ret = jent_gcd_analyze_internal(delta_history, nelem, &running_gcd,
  85. &delta_sum);
  86. if (ret == -EAGAIN)
  87. return 0;
  88. /*
  89. * Variations of deltas of time must on average be larger than 1 to
  90. * ensure the entropy estimation implied with 1 is preserved.
  91. */
  92. if (delta_sum <= nelem - 1) {
  93. ret = EMINVARVAR;
  94. goto out;
  95. }
  96. /* Set a sensible maximum value. */
  97. if (running_gcd >= UINT32_MAX / 2) {
  98. ret = ECOARSETIME;
  99. goto out;
  100. }
  101. /* Adjust all deltas by the observed (small) common factor. */
  102. if (!jent_gcd_tested())
  103. jent_common_timer_gcd = running_gcd;
  104. out:
  105. return ret;
  106. }
  107. uint64_t *jent_gcd_init(size_t nelem)
  108. {
  109. uint64_t *delta_history;
  110. delta_history = jent_zalloc(nelem * sizeof(uint64_t));
  111. if (!delta_history)
  112. return NULL;
  113. return delta_history;
  114. }
  115. void jent_gcd_fini(uint64_t *delta_history, size_t nelem)
  116. {
  117. if (delta_history)
  118. jent_zfree(delta_history,
  119. (unsigned int)(nelem * sizeof(uint64_t)));
  120. }
  121. int jent_gcd_get(uint64_t *value)
  122. {
  123. if (!jent_gcd_tested())
  124. return 1;
  125. *value = jent_common_timer_gcd;
  126. return 0;
  127. }
  128. int jent_gcd_selftest(void)
  129. {
  130. #define JENT_GCD_SELFTEST_ELEM 10
  131. #define JENT_GCD_SELFTEST_EXP 3ULL
  132. uint64_t *gcd = jent_gcd_init(JENT_GCD_SELFTEST_ELEM);
  133. uint64_t running_gcd, delta_sum;
  134. unsigned int i;
  135. int ret = EGCD;
  136. if (!gcd)
  137. return EMEM;
  138. for (i = 0; i < JENT_GCD_SELFTEST_ELEM; i++)
  139. jent_gcd_add_value(gcd, i * JENT_GCD_SELFTEST_EXP, i);
  140. if (jent_gcd_analyze_internal(gcd, JENT_GCD_SELFTEST_ELEM,
  141. &running_gcd, &delta_sum))
  142. goto out;
  143. if (running_gcd != JENT_GCD_SELFTEST_EXP)
  144. goto out;
  145. ret = 0;
  146. out:
  147. jent_gcd_fini(gcd, JENT_GCD_SELFTEST_ELEM);
  148. return ret;
  149. }