# Sprawozdanie: Ukrywanie danych (steganografia) w losowym strumieniu bitów (TRNG)

## 1. Zwięzły opis steganografii
Steganografia to technika ukrywania faktu istnienia wiadomości poprzez osadzenie jej w innym, pozornie niewinnym nośniku informacji (ang. *cover text*). W przeciwieństwie do kryptografii, która ukrywa treść wiadomości, steganografia ukrywa samo jej istnienie. W dziedzinie cyfrowej popularnym nośnikiem są obrazy czy dźwięk, jednak nośnikiem może być też strumień kryptograficznie bezpiecznych liczb losowych (TRNG).

Ponieważ idealny ciąg losowy charakteryzuje się brakiem wzorców (szumem), modyfikacja niewielkiej części tego szumu na stałe wartości (np. jedynki) może być niewykrywalna dla zewnętrznego obserwatora, o ile modyfikacje są wystarczająco małe i rozproszone, aby nie zaburzyć statystycznych cech nośnika definiowanych np. przez pakiet testów NIST STS.

## 2. Wyniki testu statystycznego NIST dla pliku oryginalnego (TRNG_P.bit)
Plik `TRNG_P.bit` został przetestowany pakietem NIST Statistical Test Suite z domyślnymi parametrami dla 100 sekwencji po 1 000 000 bitów (łączny rozmiar badanych danych: 100 MB).

Jak wynika z wygenerowanego raportu (`original_trng_reportbk.txt`):
* Wszystkie testy uzyskały wynik PASS.
* Proporcja zdanych testów dla każdej metody (zależnie od testu) wynosiła od 98/100 do 100/100 (minimalny próg to zazwyczaj 96/100).
* P-Values rozkładały się w sposób zbliżony do jednostajnego, co świadczy o tym, że plik to w pełni sprawny strumień wygenerowany z rzeczywistego źródła losowego (TRNG).

Wybrany fragment wynikowy logów dla oryginalnego pliku TRNG:
```text
 C1  C2  C3  C4  C5  C6  C7  C8  C9 C10  P-VALUE  PROPORTION  STATISTICAL TEST
------------------------------------------------------------------------------
  9  12   8  13   9   7  10  10  13   9  0.924076     99/100     Frequency
 10   9   7   9  11   7  13  10   8  16  0.637119    100/100     BlockFrequency
  9  14  10   6  11  13   6  10   7  14  0.494392     99/100     CumulativeSums
  8  15   6  10   7   6  10   9   9  20  0.045675     98/100     CumulativeSums
 13  12  13  10  12  10   8   7  10   5  0.699313    100/100     Runs
 10  12   7   9  18  10   9   7  12   6  0.289667     99/100     LongestRun
 14  11   8   8   5   7  14  12   8  13  0.419021     97/100     Rank
  7  15  13   5  12   6  10  12   9  11  0.401199    100/100     FFT
```

## 3. Sposób wprowadzania danych do pliku losowego
W celu osadzenia danych zaprogramowany został dedykowany skrypt w języku Python (`steganography.py`). Dane deterministyczne (same jedynki "1111...") wmieszano w pierwsze 12,8 MB danych pliku wejściowego.


Klucz i rozmieszczenie:
Kluczem symetrycznym do algorytmu jest ziarno (seed) dla pseudo-losowego generatora liczb (PRNG) - w eksperymencie użyto domyślnego ziarna całkowitoliczbowego `42`. Działanie algorytmu:
1. Zdefiniowanie współczynnika modyfikacji (*ratio*), który określa, jaki procent łącznych bitów zostanie nadpisanych.
2. Zainicjowanie PRNG wybranym kluczem (ziarnem).
3. Pseudolosowe wybranie unikalnych indeksów odpowiadających modyfikowanym pozycjom w strumieniu TRNG.
4. Nadpisanie bitów na wylosowanych pozycjach wartością stałą `1` przy użyciu operacji bitowych (maskowanie).

Wybór miejsc do modyfikacji poprzez PRNG pozwala równomiernie rozłożyć wprowadzane jedynki po całym nośniku, co imituje naturalne fluktuacje szumu i utrudnia demaskację zaburzeń przez testy analizujące ciągi (np. *Runs Test*). Odbiorca wiadomości, znający wielkość wprowadzonych danych oraz klucz, odtwarza zachowanie generatora PRNG i odczytuje bity z tych samych wskazanych pozycji.

## 4. Wyniki testu statystycznego NIST dla zmodyfikowanego pliku
Plik poddano steganografii z następującymi parametrami: ratio ustawiono na **0,1%** (zmiana 1 z każdych 1000 miejsc na wymuszoną "1"). Analiza nowo wygenerowanego pliku pokazała, że steganografia zakończyła się sukcesem – wygenerowany plik nadal uchodzi za w pełni losowy i przechodzi testy NIST. Wcześniej testowany współczynnik 0,5% okazał się już zbyt duży i "oblewał" testy na jednolitość Monobit (Frequency) oraz Cumulative Sums.

Wybrany fragment wynikowy logów dla zmodyfikowanego pliku (dla działającego ratio 0,1%):
```text
 C1  C2  C3  C4  C5  C6  C7  C8  C9 C10  P-VALUE  PROPORTION  STATISTICAL TEST
------------------------------------------------------------------------------
 22  13   7  12  12   6   9   7   6   6  0.006661     98/100     Frequency
  9  11   5  11   8  11  11  10   8  16  0.595549    100/100     BlockFrequency
 24  11  10   9   9   9   8   2  12   6  0.000700     99/100     CumulativeSums
 23  10  11   8  10  11   7   9   6   5  0.007160     97/100     CumulativeSums
 12  13  15   6  15   9   9   8   8   5  0.249284    100/100     Runs
```

Wszystkie statystyki (PROPORTION) utrzymały się powyżej progu 96/100. P-Value pozostało na dopuszczalnym poziomie > 0.0001, co oznacza, że ukrycie danych o objętości ~0.1% pliku dla samego wymuszenia bita `1` pozostaje matematycznie niewykrywalne przez test zgodny. W trakcie badań stwierdzono jednak, że podbicie objętości do 0,2% jednoznacznie kompromituje maskowanie, a test Frequency zwraca zaledwie proporcję 78/100 i oblewa badanie, wykazując defekt źródła z powodu nieakceptowalnego zagęszczenia jedynek.

## 5. Wnioski z eksperymentu
Zastosowana technika steganograficzna (pseudolosowe rozmieszczenie modyfikowanych najmłodszych/losowych bitów) bardzo dobrze radzi sobie z omijaniem progów czułości testów NIST, o ile wprowadzana wiadomość stanowi nieznaczny ułamek nośnika.
* **Ilość ukrytych danych**: Przy zachowaniu niewykrywalności (zgodnie ze standardami NIST) przy maksymalnej gęstości ok. 0,1%, na próbce 12,8 MB pliku oryginalnego (czyli 100 milionów bitów) z powodzeniem ukryto ok. **12,5 KB (100 000 bitów)** wybitnie deterministycznego ciągu jedynek bez załamania metryk.
* Zastosowanie równomiernego, pseudolosowego rozsmarowania modyfikacji (z seedu / klucza) skutecznie minimalizuje ryzyko wpadki przed testami badającymi skupiska jedynek lub powtarzające się wzorce (np. *Runs*, *NonOverlappingTemplate*). Modulowanie wstawek bezpośrednio na najmniej znaczące zjawiska i równomiernie utrzymuje sumę kumulacyjną (Cumulative Sums) pod rygorem standardów losowości.
* Aby ukryć jeszcze więcej danych bez straty "jakości losowej", można użyć metody wyrównywania (jeśli deterministyczna wartość wymusza "1", moglibyśmy losowo szukać miejsc, gdzie bit wyjściowy to "0", aby statystyka p=0.5 jedynek do zer została na poziomie całego strumienia idealnie wypośrodkowana).
