## Secrets v IoT
#### ako bezpečne ukladať heslá na mikrokontroléroch
[Mirek Biňas](https://bletvaska.github.io)
/ [**OSS Conf Žilina 2026**](https://ossconf.fri.uniza.sk/)
> The _S_ in _IoT_ Stands for Security.
notes:
- neda mi nezacat inac, ako standardnym vtipom na tuto temu a sice, ze oblast bezpecnosti v IoT je stale velmi problematicka
## Secrets
* **citlivé údaje**, ktoré **umožňujú prístup** k systémom, službám alebo dátam
* **musia byť bezpečne uložené a chránené pred neoprávneným prístupom**
* napr.: heslá, API kľúče, tokeny alebo certifikáty
[](https://wiki.owasp.org/index.php/OWASP_Internet_of_Things_Project#tab=IoT_Top_10)
notes:
* jednym z jej projektov je vsak aj OWASP IoT Top 10
* zoznam 10 najvacsich hrozieb v oblasti IoT
### #1 Weak, guessable or hard coded passwords
> Use of easily bruteforced, publicly available, or unchangeable credentials, including backdoors in firmware or client software that grants unauthorized access to deployed systems.

notes:
* staticka (hardcoded passwords) konfiguracia pre mqtt pripojenie
* TUYA like - posiela to na cinske servery

notes:
* to iste, len zapisane inac
* co sa stane, ak dojde k vyzradeniu loginu a hesla a admini prijmu strasne rozhodnutie, ze credentials zmenia?

notes:
* to iste, ale pre zmenu v pythone

notes:
* opat defaults pre mqtt a databazu


## Ďalšie zdroje
* tutoriály - [Random Nerd Tutorials](https://randomnerdtutorials.com/micropython-mqtt-esp32-esp8266/)
* knihy
* čo na to AI?
## Kde do $I&^% je problém?
## Secrets sú súčasťou kódu!
* hodnoty sú uložené v (globálnych) premenných
* nedajú sa zmeniť bez zmeny kódu
* sú čitateľné
* nie sú šifrované
1. **Izolácia**
Secrets uložíme do samostatného súboru.
2. **Šifrovanie**
Zašifrujeme uložené údaje, aby boli čitateľné iba s kľúčom.
3. **Binárny bytecode**
Kód pracujúci so secrets preložíme do binárneho bytecode, čím sťažíme jeho analýzu.
notes:
* Preklad do .mpy (MicroPython bytecode) sťažuje analýzu zdrojového kódu, ale nie je to bezpečnostný mechanizmus porovnateľný so šifrovaním. Skôr ide o obfuskáciu alebo sťaženie reverzného inžinierstva.
## Krok 1. Izolácia
* secrets uložíme do samostatného súboru
* použijeme formát, ktorý umožňuje jednoduché čítanie aj zápis
* vystačíme si s formátom JSON
* priama podpora v jazyku MicroPython
* umožňuje vnáranie
* výhodné je použiť dataclass pre validáciu
* `/data/settings.json`
```python
import json
SETTINGS_FILE = '/data/settings.py'
# content of settings
settings = {
"ssid": "OSS Conf 2026",
"password": "Linux.Rocks!",
}
# write settings
with open(SETTINGS_FILE, 'w') as file:
json.dump(settings, file)
# read settings
with open(SETTINGS_FILE, 'r') as file:
settings = json.load(file)
```

notes:
* https://devcookies.medium.com/encoding-vs-hashing-vs-encryption-explained-with-examples-d92b423a4584
* este predtym ako sa posunieme ku kroku 2 mi neda jedno kratke pedagogicko-terminologicke okienko
* encoding - kódovanie
* hashing - hašovanie
* encryption - šifrovanie
## Krok 2. Šifrovanie
* problém MCU pri šifrovaní - obmedzené zdroje mikrokontrolérov
* výpočtový výkon
* malá pamäť
* spotreba energie
* bezpečné ukladanie údajov (TrustZone)
* odolnosť voči fyzickým útokom
* generovanie náhodných čísiel
[](https://www.adafruit.com/product/4314)
notes:
* mozeme si pomoct napr. tak, ze k nasmu rieseniu pridame externý šifrovací koprocesor (crypto-koprocesor), ako napr ATECC608
* kľúč tak nikdy neopustí čip
[`cryptolib`](https://docs.micropython.org/en/latest/library/cryptolib.html)
## AES
Advanced Encryption Standard
* **symetrická bloková šifra**
* pracuje s blokmi o dĺžke 128 bitov / 16 bytov
* podporuje kľúče s dĺžkou 128, 192 alebo 256 bitov

notes:
- https://nordlayer.com/blog/aes-encryption/
### Get Ready!
```python
# inštancia šifry AES
>>> import cryptolib
# konštruktor AES šifry potrebuje:
# kľúč (16/24/32 bytov)
>>> key = 'SuperTajnyKluc!!'
# inicializačný vektor (vždy 16 bytov)
>>> iv = '1234567890123456'
# vytvorenie objektu šifry
>>> cipher = cryptolib.aes(key, 2, iv) # mode 2 = CBC
```
### Šifrovanie textu
```python
# majme nasledujúci text
# dĺžka musí byť násobkom 16 (PKCS#7 padding)
>>> text = 'Hello, Pico 2 W!'
# zašifrovanie textu
>>> encrypted = cipher.encrypt(text)
# výsledok bude zašifrovaný
>>> print(encrypted)
b'\xa4`\xa1\xd1(w\xe3\xe2\x13\xb4\xc8$\x04\xac\xbf\xe0'
```
### Dešifrovanie textu
```python
# pre dešifrovanie potrebujeme opäť vytvoriť objekt šifry
# (zmenil sa vnútorný stav a zmenil sa iv)
>>> cipher = cryptolib.aes(key, 2, iv)
# dešifrujeme
>>> decrypted = cipher.decrypt(bytearray(encrypted))
# výsledok je ako pole bytov
>>> decrypted
b'Hello, Pico 2 W!'
# spravíme z toho reťazec
>>> decrypted.decode('utf8')
'Hello, Pico 2 W!'
```
> A cryptosystem should be secure, even if everything about the system, **except the key**, is public knowledge.
>
> -- [Auguste Kerckhoffs](https://en.wikipedia.org/wiki/Kerckhoffs%27s_principle)

### Kľúčový problém - ako zabezpečíme kľúč?
## Krok 3. Binárny bytecode
* kľúč zostavíme ako kompozíciu z:
* `salt` - náhodne vygenerované pole bytov, ktoré budú viazané na inštaláciu
* `unique_id` - viazané na hardvér
* na šifrovanie/dešifrovanie vytvoríme vlastný modul `crypto.py`
* preložíme ho - vznikne binárny bytecode
### Vytvorenie salt
```python
import os
SALT_FILE = '/data/.salt'
def create_salt(salt_path: str) -> None:
with open(salt_path, 'wb') as file:
file.write(os.urandom(16))
```
### Vytvorenie kľúča
```python
import machine
import hashlib
def create_key(salt_path: str = SALT_FILE) -> bytes:
with open(salt_path, 'rb') as file:
salt = file.read()
hasher = hashlib.sha256()
# adding data to hash
hasher.update(machine.unique_id())
hasher.update(salt)
# return hash
return hasher.digest()[:16] # AES-128
```
### Funkcia na šifrovanie
```python
import cryptolib
import binascii
def encrypt(plaintext: str, salt_path: str = SALT_FILE) -> str | None:
if plaintext is None:
return None
key = create_key(salt_path)
iv = os.urandom(16)
data = plaintext.encode('utf-8')
pad = 16 - (len(data) % 16)
data = bytearray(data + bytes([pad] * pad))
cipher = cryptolib.aes(key, 2, iv)
encrypted = cipher.encrypt(data)
return binascii.hexlify(
bytearray(iv) + bytearray(encrypted)
).decode('ascii')
```
### Funkcia na dešifrovanie
```python
def decrypt(ciphertext: str, salt_path: str = SALT_FILE) -> str | None:
if ciphertext is None:
return None
key = create_key(salt_path)
raw = binascii.unhexlify(ciphertext)
iv = raw[:16]
data = bytearray(raw[16:])
cipher = cryptolib.aes(key, 2, iv)
decrypted = cipher.decrypt(data)
pad = decrypted[-1]
return bytes(decrypted[:-pad]).decode('utf-8')
```
## [mpy-cross](https://gitlab.com/alelec/mpy_cross )
the micropython cross compiler utility
```bash
# najprv nainštalujeme
(venv) $ pip install mpy-cross
# overíme verziu:
(venv) $ mpy-cross --version
MicroPython v1.27.0 on 2025-12-13; mpy-cross emitting mpy v6.3
# preložíme modul crypto.py
(venv) $ mpy-cross crypto.py
```
## Odkazy
* [`cryptolib`](https://docs.micropython.org/en/latest/library/cryptolib.html) - cryptographic ciphers
* [MicroPython `.mpy` files](https://docs.micropython.org/en/latest/reference/mpyfiles.html)
* [`alelec/mpy_cross`](https://gitlab.com/alelec/mpy_cross) - MicroPython `mpy-cross` distribution

(**https://bit.ly/4wnlBVO**)