The blog.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

300 wiersze
15 KiB

  1. ---
  2. title: Nearly Complete Guide to RNG on a microcontroller
  3. description: >
  4. How to initialize and run an RNG on an STM32L151CC microcontroller.
  5. created: !!timestamp '2022-02-12'
  6. time: 11:50 AM
  7. tags:
  8. - security
  9. - rng
  10. - microcontroller
  11. ---
  12. Security depends upon cryptography and which in turn depends upon a
  13. Random Number Generator (RNG). An RNG is used for key generation (both
  14. symmetric and asymmetric) and key negotiation (session establishment).
  15. The later is an absolute requirement to ensure that communications can
  16. be secured. The former (key generation) can be used at first boot for
  17. personalization, but isn't necessary as it could be done when personalizing
  18. the device at programming or first deployment.
  19. There are two types of RNGs, the first is a True Random Number Generator
  20. (TRNG). This is one that takes some non-deterministic process, often
  21. physical, and measures it. Often, these are slow and are not uniform,
  22. requiring a post processing step before the are useful.
  23. The second type is a Pseudo Random Number Generator (PRNG)<label
  24. for="sn-drbg" class="margin-toggle sidenote-number"></label><input
  25. type="checkbox" id="sn-drbg" class="margin-toggle"/><span
  26. class="sidenote">[NIST](https://www.nist.gov/) also refers to a
  27. PRNG as a Deterministic Random Bit Generator (DRBG).</span>. PRNGs
  28. take a seed, and can generate large, effectively unlimited amounts of
  29. random data, when seeded properly. The issue is than if someone is able
  30. to obtain the seed, they will be able to predict the subsequent values,
  31. allowing breaking security.
  32. The standard practice is to gather data from a TRNG, and use it to seed
  33. a PRNG. It used to be common that the PRNG should more additional random
  34. data mixed in, but I agree w/ djb (D. J. Bernstein) that once seeded, no
  35. additional seeding is needed<label for="sn-entropy" class="margin-toggle
  36. sidenote-number"></label><input type="checkbox" id="sn-entropy"
  37. class="margin-toggle"/><span class="sidenote">See his blog post
  38. [Entropy Attacks!](https://blog.cr.yp.to/20140205-entropy.html)</span>
  39. as modern PRNGs are secure and can generate random data such that their
  40. state will not leak.<label for="sn-prng-secure" class="margin-toggle
  41. sidenote-number"></label><input type="checkbox" id="sn-prng-secure"
  42. class="margin-toggle"/><span class="sidenote">That is, taking it's output,
  43. that neither past nor future output can be predicted.</span>
  44. There are lots of libraries and papers that talk about how to solve the
  45. problem for RNGs on a microcontroller that may not have an integrated
  46. [T]RNG block, but I have not been able to find a complete guide for
  47. integrating their work into a project where even a relative beginner
  48. could get it functional.
  49. This article was written as I developed the
  50. [lora-irrigation](https://www.funkthat.com/gitea/jmg/lora-irrigation)
  51. project. This project will be used as an example, and the code reference
  52. is mostly licensed under the 2-clause BSD license, and so is freely
  53. usable for your own projects.
  54. Sources of Randomness
  55. ---------------------
  56. As mentioned, most microcontrollers do not have a dedicated hardware
  57. block like modern AMD64 (aka x86-64) processors do w/ the RDRAND
  58. instruction. Though they do not, there are other sources that are
  59. available.
  60. The first, and easiest one is the Analog Digital Converter (ADC). Even
  61. if the ADC pin is tied to ground, the process of digital conversion is
  62. not 100% deterministic as there are errors in the converter or noise
  63. introduced on the pin.<label for="sn-adcnoise"
  64. class="margin-toggle sidenote-number"></label><input type="checkbox"
  65. id="sn-adcnoise" class="margin-toggle"/><span class="sidenote">The article
  66. [ADC Input Noise: The Good, The Bad, and The Ugly. Is No Noise Good
  67. Noise?](https://www.analog.com/en/analog-dialogue/articles/adc-input-noise.html)
  68. talks about this.</span>
  69. The data sheet for the microcontroller will help determine the expected
  70. randomness from the part. In the case of the
  71. [STM32L151CC](https://www.st.com/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-ultra-low-power-mcus/stm32l1-series/stm32l151-152/stm32l151cc.html)
  72. that I'm using, Table 57 of the data sheet lists the Effective number
  73. of bits (ENOB) as typically 10 bits, which is a couple bits short of
  74. the 12 bit resolution of the ADC. This means that the 2 least
  75. significant bits are likely to have some noise in them. I did a run,
  76. and collected 114200 samples from the ADC. The [Shannon
  77. entropy](https://en.wikipedia.org/wiki/R%C3%A9nyi_entropy#Shannon_entropy)
  78. calculated using the empirical probabilities was 2.48.<label
  79. for="sn-shannonenropy" class="margin-toggle sidenote-number"></label>
  80. <input type="checkbox" id="sn-shannonenropy" class="margin-toggle"/>
  81. <span class="sidenote">Now this is not strictly Shannon entropy, as the
  82. values were calculated from the experiment, and Shannon entropy should
  83. be calculated from the a priori probabilities.</span> Discarding the
  84. 0's (which makes up over half the results) improves the entropy
  85. calculation to 3.29. The
  86. [min-entropy](https://en.wikipedia.org/wiki/R%C3%A9nyi_entropy#Min-entropy)<label for="sn-min-entropy-fwdref" class="margin-toggle sidenote-number"></label>,
  87. <input type="checkbox" id="sn-min-entropy-fwdref" class="margin-toggle"/>
  88. <span class="sidenote">Forward reference:
  89. <a href="#min-entropy-awk">min-entropy awk script</a></span>
  90. a better indicator of entropy, calculation is 1.2 bits, and if all the
  91. 0's are dropped, it improves to 2.943. This does help, but in the end,
  92. subtracting the data sheet's ENOB from the ADC resolution does result
  93. in an approximate estimate of entropy.
  94. It is possibly that a correlation analysis between samples could
  95. further reduce the entropy gathers via the ADC, but with sufficient
  96. collection, this should be able to be avoided.
  97. The second is using uninitialized SRAM. It turns out that this has
  98. been studied in [Software Only, Extremely Compact, Keccak-based Secure
  99. PRNG on ARM Cortex-M](https://dl.acm.org/doi/10.1145/2593069.2593218)
  100. and [Secure PRNG Seeding on Commercial Off-the-Shelf
  101. Microcontrollers](https://www.intrinsic-id.com/wp-content/uploads/2017/05/prng_seeding.pdf).
  102. Depending upon how the SRAM is designed in the chip, it can create a
  103. situation where each bit of SRAM will be indeterminate at boot up.
  104. Both of these papers studied a similar microcontroller, an
  105. STM32F100R8 to the one I am using, a STM32L151CC.
  106. I ran my own experiments where I powered on an STM3L151CC and dumped
  107. the SRAM 8 times and analyzed the results. I limited my analysis to
  108. 26863 bytes the 32 KiBytes of ram (remaining was data/bss or stack, so
  109. would not change, or was zeros). I then calculated the min-entropy for
  110. each bit across power cycles and the resulting sum was 11188, or
  111. approximately .416 bits per byte. This is 5.2% and in line with what
  112. the later paper observed for a similar device.
  113. Part of using a source of randomness is making sure that it is usable.
  114. In the case of the ADC, each reading can be evaluated against previous
  115. reads to ensure that the data being obtained is possibly random. In
  116. the case of SRAM, this is more tricky, as the state of SRAM is static,
  117. and short of a reset, will not change. This means that to use SRAM,
  118. proper analysis of the device, or family of devices, need to be evaluated
  119. for suitability. There are cases where a device's SRAM does not provide
  120. adequate entropy, as discussed in the papers, and so this method should
  121. not be used in those cases, or not solely relied upon.
  122. The following is an `awk` script for calculating the min-entropy of the
  123. provided data. Each sample must be the first item on a line, and each
  124. sample must be a hexadecimal value w/o any leading `0x` or other leading
  125. identifier:
  126. <pre id="min-entropy-awk" class="language-awk fullwidth"><code># Copyright 2021 John-Mark Gurney
  127. # This script is licensed under the 2-clause BSD license
  128. function max(a, b)
  129. {
  130. if (a > b)
  131. return a;
  132. else
  133. return b;
  134. }
  135. {
  136. v = ("0x" $1) + 0; a[NR] = v;
  137. maxv = max(maxv, v);
  138. }
  139. END {
  140. tcnt = length(a);
  141. me = 0;
  142. for (bit = 0; 2^bit <= maxv; bit += 1) {
  143. cnt0 = 0;
  144. cnt1 = 0;
  145. for (i in a) {
  146. tbit = int((a[i] / 2 ^ bit) % 2);
  147. if (tbit)
  148. cnt1 += 1;
  149. else
  150. cnt0 += 1;
  151. }
  152. v = -log(max(cnt0, cnt1) / tcnt) / log(2);
  153. print "bit " bit ":\t" v;
  154. me += v;
  155. }
  156. printf "total:\t%0.3f\n", me;
  157. }
  158. </code></pre>
  159. It is also possible that there are other parts of the board/design
  160. that could be a source of randomness. The project that started this
  161. journey is using [LoRa](https://en.wikipedia.org/wiki/LoRa) for
  162. communication. It turns out that the sample code for the radio chip
  163. ([LoRaMac&#x2011;node](https://github.com/Lora-net/LoRaMac-node)) implements
  164. a [random interface](https://github.com/Lora-net/LoRaMac-node/blob/7f12997754ad8e38a84daa85f62e7e6c0e5dbe59/src/radio/radio.h#L154-L163).
  165. The function just waits one milisecond, reads the RSSI value, takes
  166. the low bit and repeats this 32 times to return a 32-bit word. There
  167. are issues with this as I cannot find any description of the expected
  168. randomness in the data sheet, nor in the code. It also does not do
  169. any conditioning, so just because it returns 32-bits, does not guarantee
  170. 32-bits of usable entropy. I have briefly looked at the output, and
  171. there does appear to be higher lengths of runs than expected. Another
  172. issue is that it's collection takes a while, as the fastest is 1 bit
  173. per ms. So, assuming the need to collect 8 bits for 1 bit of entropy
  174. (pure speculation), that means at minimum 2 seconds to collect the
  175. 2048 bits necessary for 256 bits of entropy.
  176. Uniquifying
  177. -----------
  178. One of the other ways to help ensure that a microcontroller is to
  179. integrate per device values into the PRNG. This does not guarantee
  180. uniqueness between boots, but it does make it harder to attack if an
  181. attacker is able to control the other sources of randomness.
  182. In the case of the STM32L151 chip I am using, there is a unique
  183. device id register. The device register is programmed at the
  184. factory. Because it is unknown if this unique id is recorded by the
  185. manufacturer, and possibly traced through the supply chain, and no
  186. guarantees are made to both the uniqueness or privacy, it has limited
  187. use to provide any serious additional randomization.
  188. Another method, is to write entropy at provisioning time. This can be
  189. done in either flash memory or EEPROM, which may have a more granular
  190. write access.
  191. Using SRAM
  192. ----------
  193. The tricky part of using SRAM is figuring out how to access the
  194. uninitialized memory. Despite having full access to the environment,
  195. modifying the startup code, which is often written in assembly, to do
  196. the harvesting makes an implementation less portable. Using standard
  197. C, or another high level language, makes this easier, *but* we need to
  198. know where the end of the data and bss segments are. This is where
  199. looking at the linker script will come in.
  200. A linker script is used to allocate and map the program's data to the
  201. correct locations. This includes allocating memory so that all the
  202. code and data fits in flash, but also allocating ram for variables, and
  203. stack. Often there will be a symbol provided that marks where the data
  204. and bss sections in ram end, and the heap should begin. For example,
  205. in [`STM32L151CCUX_FLASH.ld` at lines 185 &
  206. 186](https://www.funkthat.com/gitea/jmg/lora-irrigation/src/commit/91a6fb590b68af1bcd34f776d4a58c89ac581c7d/stm32/l151ccux/STM32L151CCUX_FLASH.ld#L185-L186)
  207. it defines the symbols `end` and `_end`, the later of which is often
  208. used by `sbrk` (or `_sbrk` in my project's case in
  209. libnosys<label for="sn-sbrk-sample" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-sbrk-sample" class="margin-toggle"/>
  210. <span class="sidenote">A sample `_sbrk` is in [utils_syscalls.c](https://www.funkthat.com/gitea/jmg/lora-irrigation/src/commit/91a6fb590b68af1bcd34f776d4a58c89ac581c7d/loramac/src/boards/mcu/saml21/hal/utils/src/utils_syscalls.c#L67-L83),
  211. though this particular implementation is not used by my project.</span>)
  212. to allocate memory for the heap. Using sbrk is the easiest method to
  213. access uninitalized SRAM, but modifying or adding a symbol can be used
  214. if your microcontroller's framework does not support sbrk.
  215. Putting it together
  216. -------------------
  217. It is accepted that integrating as many difference sournces of entropy
  218. (TRNGs) is best. This ensures that as long as any single soruce is
  219. good, or each one is not great, but combined they provide enough
  220. entropy (preferably at least 128 bits), that the seeded PRNG will be
  221. secure and unpredictable.
  222. As some sources are only available at first boot, e.g. SRAM, it is
  223. best to save a fork of the PRNG to stable storage. In my
  224. implementation, I decided to use EEPROM for this. I added an
  225. additional EEPROM section in the linker script, and then added a symbol
  226. [rng_save](https://www.funkthat.com/gitea/jmg/lora-irrigation/src/branch/main/strobe_rng_init.c#L39)
  227. that is put in this section. This should be 256-bits (32-bytes) as
  228. the savings of smaller does not make sense, and any proper PRNG when
  229. seeded with 256-bits will provide enough randomness. Writing to EEPROM
  230. does require a little more work to have the code save to this region,
  231. rather than RAM, but the STM32 HAL layer has functions that make this
  232. easy.
  233. It would be great if the PRNG seed could be stored in read-once,
  234. write-once memory to ensure that it can be read, mixed in with any
  235. additional entropy, and then written out, but I do not know of any
  236. microcontroller that supports this feature.
  237. Part of this is is to ensure that the the state between the saved
  238. seed, and the PRNG state used for this boot is disjoint, and that if
  239. either seed is compromised, neither can be backtracked to obtain the
  240. other. In the case of [strobe](https://strobe.sourceforge.io/papers/strobe-latest.pdf),
  241. the function [strobe_randomize](https://www.funkthat.com/gitea/jmg/lora-irrigation/src/branch/main/strobe/strobe.c#L319-L331)
  242. does a RATCHET operation at the end, which ensure the state cannot be rolled
  243. back to figure out what was generated, and as the generated bytes does
  244. not contain the entire state of the PRNG, it cannot be used to
  245. reconstruct the future seed.
  246. Another advantage of using EEPROM is the ability to provide an initial
  247. set of entropy bytes at firmware flashing time. I did attempt to add
  248. this, but OpenOCD, which I use for programming the Node151 device,
  249. does not support programming EEPROM, so in my case, this was not
  250. possible<label for="sn-eeprom-flash" class="margin-toggle sidenote-number"></label><input type="checkbox" id="sn-eeprom-flash" class="margin-toggle"/><span class="sidenote">Despite not using it, the infrastructure to generate perso entropy is still present in the [Makefile](https://www.funkthat.com/gitea/jmg/lora-irrigation/src/branch/main/Makefile#L152-L157).</span>.
  251. I could have added an additional source data file to the flash, but
  252. figured that the other sources of entropy were adequate enough for my
  253. project.
  254. {#
  255. Conclusion
  256. ----------
  257. Modern microcontrollers do have a number of sources of entropy that can
  258. be used. With a little bit of work, a PRNG seed can be saved between
  259. resets, allowing for more secure operation, and even preloading of
  260. entropy. #}