W tym poście chciałbym opisać funkcje TRNG (ang. True Random Number Generator).
TRNG jest to sprzętowy generator licz losowych opartych na zjawiskach fizycznych. Oznacza to, że generuje on liczby losowe nieprzewidywalne i niereprodukowane. Są one idealne do zastosowań kryptograficznych.
Dokładny opis [link]
TRNG bazuje na źródle szumu analogowego. Generator tworzy zestaw czterech 32-bitowych liczb losowych. Dla przedstawionych danych próbki są dostępne co 864 cykle AHB.
Trzy flagi statusowe:
- DRDY - (ang. Data Ready) - dane są gotowe do odczytania z rejestru DR.
- SECS - (ang. Seed Error Current Status) - pojawiły się nieprawidłowe dane w ciągu bitów źródła entropii. np. Ponad 64 identyczne bity z rzędu bądź 32 powtarzane wzorce jak 01, 10.
- CECS - (ang. Clock Error Current Status) - za niska częstotliwość.
Trzy przerwania:
- CEIS - (ang. Clock Error Interrupt Status) - Przerwanie sygnalizujące problem z zegarem.
- SEIS - (ang. Seed Error Interrupt Status) - Przerwanie sygnalizujące błąd entropii
- DRDY - (ang. Data Ready Interrupt) - Dane dostępne do odczytu.
Diagram blokowy wygląda następująco:
Schemat został podzielony na następujące bloki:
- Analog Seed - źródło entropii generowane na podstawie analogowego szumu.
- Sampling - proces próbkowania.
- Digital post-processing/conditioning - Dane ze źródła analogowego są przetwarzane cyfrowo aby poprawić rozkład losowości oraz usunięcie korelacji miedzy bitami.
- 4x 32-bit FIFO - bufor dla danych losowych.
- 32-bit random data register - końcowy punkt z którego można odczytać gotowe dane losowe.
- Error management - składa się z dwóch bloków:
- Clock checker - sprawdzanie poprawności zegara. Zgłaszanie błędów jeśli takie problemy się pojawią.
- Fault detector - wykrywanie błędów np. związanych z brakiem entropii bądź powtarzalności danych.
Działanie bloku jest następujące:
- Start RNG,
- Analogowy szum jest próbkowany i przetwarzany.
- Wynik operacji trafia do FIFO. Następnie do rejestru DR.
- Gdy dane są gotowe ustawiana jest flaga DRDY.
- Jeśli operacja się nie powiedzie, ustawiane są flagi SEIS/CEIS.
Bezpośrednio z CubeMx można uruchomić flagę ClockErrorDetection oraz przerwania od RNG:
Rejestry RNG:
- #define RNG_SR_DRDY_Pos (0U)
- #define RNG_SR_DRDY_Msk (0x1UL << RNG_SR_DRDY_Pos) /*!< 0x00000001 */
- #define RNG_SR_DRDY RNG_SR_DRDY_Msk
- #define RNG_SR_CECS_Pos (1U)
- #define RNG_SR_CECS_Msk (0x1UL << RNG_SR_CECS_Pos) /*!< 0x00000002 */
- #define RNG_SR_CECS RNG_SR_CECS_Msk
- #define RNG_SR_SECS_Pos (2U)
- #define RNG_SR_SECS_Msk (0x1UL << RNG_SR_SECS_Pos) /*!< 0x00000004 */
- #define RNG_SR_SECS RNG_SR_SECS_Msk
- #define RNG_SR_CEIS_Pos (5U)
- #define RNG_SR_CEIS_Msk (0x1UL << RNG_SR_CEIS_Pos) /*!< 0x00000020 */
- #define RNG_SR_CEIS RNG_SR_CEIS_Msk
- #define RNG_SR_SEIS_Pos (6U)
- #define RNG_SR_SEIS_Msk (0x1UL << RNG_SR_SEIS_Pos) /*!< 0x00000040 */
- #define RNG_SR_SEIS RNG_SR_SEIS_Msk
Dane można odczytać bezpośrednio z rejestrów. Poniżej funkcje pozwalające na takie operacje:
- uint8_t RNG_IsDataReady(void)
- {
- return (RNG->SR & RNG_SR_DRDY) ? 1 : 0;
- }
- uint8_t RNG_IsClockErrorCurrent(void)
- {
- return (RNG->SR & RNG_SR_CECS) ? 1 : 0;
- }
- uint8_t RNG_IsSeedErrorCurrent(void)
- {
- return (RNG->SR & RNG_SR_SECS) ? 1 : 0;
- }
- uint8_t RNG_IsClockErrorInterrupt(void)
- {
- return (RNG->SR & RNG_SR_CEIS) ? 1 : 0;
- }
Testowa funkcja generująca 20 liczb losowych:
- for(uint8_t i=0; i<20;i++) {
- uint32_t randomNumber = 0;
- HAL_RNG_GenerateRandomNumber(&hrng, &randomNumber);
- printf("[%.2d] 0x%08lX\r\n",i,randomNumber);
- }
Przykładowe generowanie liczb losowych:
- [00] 0x4A37657E
- [01] 0x982B4CE2
- [02] 0x02FF5B05
- [03] 0xB63EED7A
- [04] 0xC516AF68
- [05] 0xBC797E86
- [06] 0x094F7622
- [07] 0x18E81C6F
- [08] 0x9D76AF46
- [09] 0x9E3D7359
- [10] 0x65986F55
- [11] 0x4D296E40
- [12] 0x382F13D3
- [13] 0xD06EA165
- [14] 0x31DD1B3D
- [15] 0x431A45BF
- [16] 0x7C8327E4
- [17] 0x2A79581D
- [18] 0xBE549B27
- [19] 0x7E678273