Technika
Dla tych, którzy chcą wiedzieć dokładnie: formaty, parametry, konstrukcje — i miejsca, w których świadomie niczego nie obiecujemy.
Plik sejfu to jawny, ale chroniony MAC-iem nagłówek i zaszyfrowany korpus. W nagłówku stoi wyłącznie to, co potrzebne do wyprowadzenia klucza: sól, parametry KDF i rodzaje czynników. Cała reszta — wpisy, notatki, zdjęcia oraz warunki dostępu — leży w korpusie.
Do wersji 3 współrzędne i data otwarcia stały w jawnym nagłówku. W aplikacji, której zadaniem jest ukryć, gdzie leżą kosztowności, był to produkt zdradzający własny przedmiot. Od wersji 4 są w korpusie, a konsekwencja jest zamierzona: warunki da się odczytać dopiero po odszyfrowaniu.
Plik zawsze zawiera dwa miejsca. Nigdy nieskonfigurowane drugie miejsce jest wypełniane danymi losowymi tej samej długości i nie da się go odróżnić od prawdziwego — z pliku nie wynika więc, czy drugi sejf istnieje.
| Parametr | Wartość |
|---|---|
version | 4 |
| AEAD | AES-256-GCM |
| KDF | Argon2id (libsodium), opsLimit 2, memLimit 64 MiB, p = 1 |
| KDF (Altbestand) | PBKDF2-HMAC-SHA256, 600 000 |
| HKDF | HKDF-SHA256, reine Dart-Implementierung |
| Slots | 2 (immer beide vorhanden) |
| Wraps je Slot | 2 — Faktorpfad, Notfallpfad |
Z czynników Argon2id tworzy klucz bazowy. Argon2id jest twardy pamięciowo: 64 MiB na próbę uderza w napastnika ze sprzętem specjalnym znacznie mocniej niż same rundy obliczeń. Na urządzeniu z 2024 roku próba kosztuje około sekundy; PBKDF2 przy porównywalnie uczciwej liczbie rund mierzył od kilku do ponad dwudziestu sekund, bo Android nie oferuje dla niego ścieżki natywnej.
Klucz bazowy niczego nie odszyfrowuje wprost. Szyfrowanie idzie losowym kluczem korpusu, opakowanym dwukrotnie: raz ścieżką czynników, raz ścieżką awaryjną. Tam, gdzie ścieżka nie jest używana, stoi atrapa tej samej długości. Dwie konsekwencje: kosztowny Argon2id liczy się raz, niezależnie od liczby sprawdzanych pól, a nagłówek nie zdradza, jaki sejf trzymasz w ręku.
Pliki jako część klucza idą przez Shamira nad GF(28) z wielomianem
Rijndaela 0x11B: albo wszystkie N w ustalonej kolejności, albo
dowolne K z nich jako droga awaryjna.
Miejsce nie jest pytaniem zadawanym przez aplikację, tylko częścią planu klucza. Pozycja jest kwantowana na siatkę, z pola liczony jest identyfikator, a ten identyfikator wchodzi jako sól do wyprowadzenia klucza ścieżki:
masterKey = HKDF(baseKey, salt = identyfikator pola)
Poza polem klucz zatem nie istnieje — nie ma czego obejść ani zmienioną aplikacją, ani podstawionym GPS-em. Sejf jest związany z dokładnie jednym polem; promień szukania mówi tylko, ile pól sąsiednich sprawdza klient, więc kosztuje czas, a nie bezpieczeństwo.
| Parametr | Wartość |
|---|---|
| Raster | 50 m, metrisch quantisiert |
| Zellkennung | SHA-256 über tva:geo:v1:… |
| Ableitung | HKDF-SHA256, salt = Zellkennung |
| Suchradius | 150 / 300 / 600 / 1200 m |
| Kandidaten | 25 / 121 / 529 / 2209 Zellen |
| Kosten (razr 50 ultra) | 72 / 162 / 220 / 385 ms |
| Gespeichert | nichts — weder Koordinaten noch Zelle noch Radius |
Kapsuła czasowa to implementacja beattime-seal-v1. Klucz notatki
jest dzielony metodą Shamira; udziały beaconów szyfruje się
szyfrowaniem opartym na tożsamości (Boneh–Franklin nad
BLS12-381) na tożsamość wynikającą z chwili otwarcia. Odpowiadająca jej
„prywatna” połowa to podpis, który beacon publikuje w tej chwili — wcześniej
nie istnieje, także u operatora.
Arytmetyka par leży we własnej bibliotece w Ruście na
ark-bls12-381. Popularna skrzynka tlock nie
jest używana: ma zaszyte 16-bajtowe sigma, bo szyfruje wyłącznie klucze plików
age. Referencja losuje sigma o długości wiadomości — przy 32 bajtach
pieczętowanych tutaj obie dają różne szyfrogramy i żadna nie otworzy drugiej.
Przez granicę C nie jest alokowane nic, co ktoś musiałby zwolnić: oba wyniki mają długość policzalną z góry, bufor daje wołający, a każdy punkt wejścia przechwytuje paniki.
| Parametr | Wartość |
|---|---|
| Format | beattime-seal-v1 |
| Hauptgeheimnis | 32 B, Shamir über GF(28), Polynom 0x11B |
| Nutzlast | AES-256-GCM-STREAM, Segment 65 536 B |
| Nonce | Präfix 7 B ‖ Zähler 4 B BE ‖ last 1 B |
| AAD | SHA-256 des kanonischen Kopfs |
| Schlüssel | HKDF-SHA256, info = beattime-seal-v1|aead |
| IBE | Boneh–Franklin über BLS12-381 |
| Kurvenschema | bls-unchained-g1-rfc9380 |
| Chiffrat | U 96 B (G2) ‖ V 32 B ‖ W 32 B |
| Beacons | drand quicknet + BeatTime-Schlüsselserver |
| Profil | standard — 2 von 3 |
Zdjęciu zrobionemu w aplikacji można wystawić dowód istnienia. Przesyłana jest suma SHA-256, nigdy obraz. Serwis umieszcza wartość w liściu drzewa Merkle; po zamknięciu tygodnia korzeń podpisywany jest Ed25519. Aplikacja zapisuje sumę, czas, dowód inkluzji i podpis, a cały dowód przelicza offline: od zdjęcia do liścia, od liścia do korzenia, podpis wobec klucza publicznego.
To dowód skierowany wstecz — „to istniało już wtedy” — i dlatego wyraźnie nie jest zamkiem czasowym. Zamek czasowy wymaga kierunku przeciwnego i od tego są kapsuły.
Format, który rozmawia wyłącznie sam ze sobą, niczego nie dowodzi. Trzy sprawdzenia idą przeciwko cudzemu kodowi, po jednym na warstwę:
tlock-js i odwrotnie; do tego wobec podpisu, który drand
naprawdę opublikował.Do tego testy na prawdziwym sprzęcie: że biblioteka arm64 ładuje się w pakiecie, że kapsuła z miejscem nie otwiera się w innym mieście, i ile to wszystko kosztuje — parowanie wychodzi około 10 ms.