piątek, 12 grudnia 2025

STM32 - Funkcje bezpieczeństwa - Tamper

W tym poście chciałbym opisać kolejną z funckji bezpieczeństwa w układach STM32, którą jest Tamper. 



Tamper jest zaimplementowane we wszystkich układach z rodziny STM32. 


Po co właściwie korzystać z takiego tampera? Czy nie można po prostu wykonać to w oparciu o zwykły pin GPIO? No właściwie to można, ale nie będzie on taki dobry jak ten z Security Features. 

Jeśli weźmiemy pod uwagę zwykły pin to musimy zaimplementować go np. w przerwaniu. Jeśli urządzenie z jakiegoś powodu nie będzie działać lub zostanie zatrzymane to zmiana stanu na tym pinie będzie niezauważalna. 

Tamper sprzętowy natomiast jest powiązany z modułem PWR/TAMP. Gdy mikrokontroler nie wykonuje programu np. w trybie Stop czy Stanby, dalej zmiana stanu zostanie zauważona. Dodatkowo pozwala on na czyszczenie Backup Registers czy zarejestrować czas naruszenia bazując na RTC tamper timestamp. Czyli zapewnia on bezpieczeństwo na poziomie sprzętu, a nie tylko rejestruje zmianę stanu na pinie.

Przykład będę opierał na układzie STM32H723. W nim można przypisać dwa tampery (Tamper 1 - PC13, Tamper 3 - PC1). 


Pin PC13 jest podłączony bezpośrednio do przycisku. Przez co jego kliknięcie spowoduje uruchomienie tampera.

Zaczniemy od podstawowej konfiguracji. Poniżej kod wygenerowany automatycznie przez CubeMx:

  1. void MX_RTC_Init(void)
  2. {
  3.   RTC_TamperTypeDef sTamper = {0};
  4.   hrtc.Instance = RTC;
  5.   hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  6.   hrtc.Init.AsynchPrediv = 127;
  7.   hrtc.Init.SynchPrediv = 255;
  8.   hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  9.   hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  10.   hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  11.   hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  12.   if (HAL_RTC_Init(&hrtc) != HAL_OK)
  13.   {
  14.     Error_Handler();
  15.   }
  16.  
  17.   /** Enable the RTC Tamper 1 */
  18.   sTamper.Tamper = RTC_TAMPER_1;
  19. //Zbocze zadziałania
  20.   sTamper.Trigger = RTC_TAMPERTRIGGER_RISINGEDGE;
  21. //Automatyczne kasowanie rejestrów backup
  22.   sTamper.NoErase = RTC_TAMPER_ERASE_BACKUP_ENABLE;
  23. //Wykrywanie kolejnych zdarzen, brak maskowania po pierwszym zdarzeniu
  24.   sTamper.MaskFlag = RTC_TAMPERMASK_FLAG_DISABLE;
  25. //Filtr antyzakłoceniowy, tutaj wyłączony, można włączyć jeśli pojawiają się zakłócenia
  26.   sTamper.Filter = RTC_TAMPERFILTER_DISABLE;
  27.   sTamper.SamplingFrequency = RTC_TAMPERSAMPLINGFREQ_RTCCLK_DIV32768;
  28. //Konfiguracja filtru antyzakłóceniowego.
  29.   sTamper.PrechargeDuration = RTC_TAMPERPRECHARGEDURATION_1RTCCLK;
  30.   sTamper.TamperPullUp = RTC_TAMPER_PULLUP_ENABLE;
  31. //Automatyczne zapisanie daty i czasu naruszenia
  32.   sTamper.TimeStampOnTamperDetection = RTC_TIMESTAMPONTAMPERDETECTION_ENABLE;
  33.   if (HAL_RTCEx_SetTamper(&hrtc, &sTamper) != HAL_OK)
  34.   {
  35.     Error_Handler();
  36.   }
  37. }

Włączenie przerwań:

  1. void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
  2. {
  3.   RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  4.   if(rtcHandle->Instance==RTC)
  5.   {
  6.   /* USER CODE BEGIN RTC_MspInit 0 */
  7.   /* USER CODE END RTC_MspInit 0 */
  8.  
  9.   /** Initializes the peripherals clock
  10.   */
  11.     PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  12.     PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
  13.     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  14.     {
  15.       Error_Handler();
  16.     }
  17.  
  18.     /* RTC clock enable */
  19.     __HAL_RCC_RTC_ENABLE();
  20.  
  21.     /* RTC interrupt Init */
  22.     HAL_NVIC_SetPriority(TAMP_STAMP_IRQn, 0, 0);
  23.     HAL_NVIC_EnableIRQ(TAMP_STAMP_IRQn);
  24.   /* USER CODE BEGIN RTC_MspInit 1 */
  25.   /* USER CODE END RTC_MspInit 1 */
  26.   }
  27. }

  1. void TAMP_STAMP_IRQHandler(void)
  2. {
  3.   /* USER CODE BEGIN TAMP_STAMP_IRQn 0 */
  4.  
  5.   /* USER CODE END TAMP_STAMP_IRQn 0 */
  6.   HAL_RTCEx_TamperTimeStampIRQHandler(&hrtc);
  7.   /* USER CODE BEGIN TAMP_STAMP_IRQn 1 */
  8.  
  9.   /* USER CODE END TAMP_STAMP_IRQn 1 */
  10. }

Funkcja obsługi Eventu od tampera została opisana w bibliotece:

  1. _weak void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef * hrtc)
  2. {
  3.   /* Prevent unused argument(s) compilation warning */
  4.   UNUSED(hrtc);
  5.  
  6.   /* NOTE : This function should not be modified, when the callback is needed,
  7.             the HAL_RTCEx_Tamper1EventCallback could be implemented in the user file
  8.    */
  9. }

Ma ona definicję weak co oznacza, że można ją nadpisać:

  1. void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef *hrtc) {
  2.     HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14);
  3. }

W niej można np. zapisać zdarzenie w logu, wyzerować dodatkowe dane, wymusić restart systemu czy wywołać alarm przez wysterowanie któregoś z pinów czy jak w tym przypadku zapalić diodę. Bez dodatkowej ingerencji ze strony użytkownika następuje automatyczne czyszczenie rejestru backup (jeżli RTC_TAMPER_ERASE_BACKUP_ENABLE). 

Ok a teraz najważniejsze po co stosować taki mechanizm:
  • W celu ochrony kluczy kryptograficznych. W odpowiednim momencie możemy je skasować z urządzenia.
  • Dostajemy pewną informację o otwarciu obudowy, któe mogą oznaczać, że któś prubuje majstrować przy urządzeniu.