Confidex
Sekce

Jak může server ukládat a synchronizovat naše tajemství, aniž by musel držet klíče k jejich čtení? Budeme sledovat, jak Confidex vytváří své klíče, chrání je v zámku a používá je k šifrování dat a ověřování změn.

Zámek

Jen Vyvolený může otevřít dveře

Matrix Reloaded

Představte si, že budujeme virtuální vault pro ukládání tajných dat. Po ukončení aplikace musí tato data uchovat v notebooku a nechat nás otevřít na jiném zařízení. Trezor bude potřebovat vlastní klíče. Musíme je uložit tak, aby zkopírování souborů neposkytlo nepovolaným osobám žádný způsob, jak číst nebo měnit jejich obsah.

Klíče chrání lock: malý zašifrovaný soubor. Jeho otevření vyžaduje hlavní heslo a tajný kód, secret_key; ani jedno není v samotném souboru. Mohli bychom vytisknout celý zámek v ranních novinách. Čtenáři by dostali kopii, ale její zveřejnění by neodhalilo soukromé klíče.

Předpokládejme, že někdo zvenčí získá tento soubor a dokonce se naučí hlavní heslo. Nyní mohou opakovat každý výpočet, který vyžaduje pouze heslo, ale tyto výpočty nevytvoří klíč, který otevře zámek: secret_key je také vstup. Soubor neobsahuje žádnou samostatnou kontrolu samotného hesla. Jeho otevření stále vyžaduje neznámý tajný kód.

Tento kód pochází z kryptograficky náhodných dat; to si člověk nevymyslí. Dokud je secret_key neznámé, ani správně uhodnuté hlavní heslo zámek neotevře: útočníkovi stále chybí náhodné tajemství. Samotné slabé heslo tedy nepromění kopii serveru v praktický slovníkový útok.

Pokud útočník získá také secret_key, může testovat uhodnutí hlavního hesla offline. To je nákladné, ale případná obtížnost závisí na síle hesla.

Klíče

Pánové, co dělají klíče? Klíče… odemknout věci?

Piráti z Karibiku – Truhla mrtvého muže

Aplikace získá 32 náhodných bajtů z kryptografického generátoru operačního systému a připraví je pro použití jako klíč. Tyto připravené bajty jsou soukromý hlavní klíč, master_key.

Aplikace vždy odvozuje stejné klíče z master_key: opakování stejných výpočtů na stejných bajtech dává stejný výsledek. Notebook a telefon tedy mohou obnovit stejné klíče. Chcete-li získat master_key na novém zařízení, musí aplikace nejprve otevřít zámek pomocí hlavního hesla a secret_key.

První pár: šifrování

Jsem Keymaster.

Krotitelé duchů

Pro uložení zašifrovaných dat vypočítá aplikace veřejný klíč z master_key: secret_key. Může šifrovat data pro trezor, zatímco dešifrování vyžaduje master_key.

„Veřejné“ popisuje roli tohoto klíče v algoritmu, nikoli povinnost dát jej každému. V Confidex zůstane uživateli. Je to také druhé tajemství potřebné k otevření zámku, takže zůstává lokální a není odesíláno přes síť. secret_key sám o sobě umožňuje někomu zašifrovat data pro trezor, ale ne dešifrovat je ani podepisovat změny jeho jménem.

X25519 je algoritmus, který bere master_key a počítá secret_key. Obnovení master_key z secret_key je prakticky neproveditelné. Klasický útok na imaginární superpočítač provádějící miliardu miliard operací s křivkami za sekundu by v průměru trval asi 2,3 bilionu let (odhad SafeCurves).

public bytes Random bytes32 bytes master_key secret_key public bytes Random bytes32 bytes master_key secret_key
Od náhodných bajtů po šifrovací klíče.

Druhý pár: podpisy

Jediné, co je originální, je podpis

Chyť mě, jestli to dokážeš

První pár pomáhá skrýt obsah. Nyní potřebujeme způsob, jak potvrdit, že vlastník trezoru schválil změnu. Server musí být také schopen kontrolovat podpisy, takže mu musíme poslat veřejný ověřovací klíč. Veřejná část prvního páru je secret_key, kterou server nesmí přijmout. Vytváříme proto druhý, trvalý pár klíčů pro podpisy.

Místo uložení dalšího nezávislého tajemství odvozujeme soukromý podpisový klíč z master_key a nazýváme ho signing_key. Aplikace jej používá k podepisování dat a zámku. Ostatní zařízení a server používají svou veřejnou část ke kontrole podpisů bez čtení obsahu.

Můžeme obnovit tento pár ze stejného master_key. Aplikace z něj odvozuje počáteční hodnotu: 32 bajtů, které jednoznačně určují podpisový klíč.

Abychom odvodili různé klíče pro různé úlohy, zahrneme do výpočtu pevné označení: zde confidex/vault/ed25519/v1. Stejný master_key a stejný štítek vždy vytvářejí stejný klíč.

Hlavní heslo tyto výpočty nezadalo. Oba páry závisí na náhodných bajtech master_key, nikoli na řetězci vymyšleném osobou. Na tomto rozlišení bude později záležet: heslo bude chránit přístup ke klíčům, které již existují, takže jej můžeme změnit, aniž bychom měnili samotné klíče.

Odvozování používá funkci odvození klíče na bázi hash: HKDF, HMAC-based Extract-and-Expand Key Derivation Function. Confidex jej používá s SHA-256, odtud název HKDF-SHA256. Výsledných 32 bajtů je seed pro pár Ed25519. Veřejná část signing_key neodhaluje secret_key, takže ji můžeme odeslat na server k ověření podpisu.

public bytes HKDF-SHA256keymaster_keyinfo"confidex/vault/ed25519/v1" signing_key Signature verification public bytes HKDF-SHA256keymaster_keyinfo"confidex/vault/ed25519/v1" signing_key Signature verification
Samostatný podpisový klíč odvozený ze stejného hlavního klíče.

Co je soubor zámku a k čemu slouží?

Otevři dveře kabiny, HAL.
Je mi to líto, Dave. Obávám se, že to nedokážu.

Vesmírná odysea

V zámku je uložen zašifrovaný master_key. Jeho otevření vyžaduje hlavní heslo a secret_key. Veřejné záhlaví obsahuje verzi formátu, identifikátor vaultu, veřejnou část signing_key, sůl a parametry zpracování hesla. Verze interního formátu je zašifrována spolu s master_key.

Při vytváření zámku má aplikace již master_key, takže před zašifrováním vypočítá secret_key. Při jeho otevření uživatel dodá secret_key samostatně: ve veřejné kopii zámku chybí.

Po dešifrování aplikace vypočítá veřejnou část master_key pomocí X25519 a vyžaduje, aby odpovídala secret_key. Poté obnoví signing_key a porovná jeho veřejnou část s klíčem v záhlaví. Tímto způsobem se zámek sám zkontroluje.

Chcete-li zpomalit hádání hlavního hesla, každý pokus musí stát čas a paměť. Confidex používá Argon2id s 64 MiB paměti a třemi průchody. Zpracování hesla také používá náhodnou sůl. Sůl není tajná: způsobuje, že stejné heslo produkuje různé výsledky v různých zámcích.

Pokud je secret_key již známo, délka hesla dramaticky změní rozsah útoku. Existuje asi 12 milionů kombinací 5 náhodných malých latinských písmen, asi 8 miliard ze 7 a asi 9,5 × 10¹⁶ z 12. Přechod ze 7 na 12 písmen zvětší vyhledávací prostor téměř 12 milionůkrát. Pokud by hledání 7 písmen trvalo na daném stroji v průměru jeden den, 5 by trvalo asi dvě minuty a 12 asi 33 000 let.

K získání jednoho klíče z výsledku Argon2id a secret_key použijeme dříve představenou funkci HKDF-SHA256 s označením confidex/lock/wrap/v1. Výsledkem je wrapping_key, klíč, který zašifruje zámek.

Musíme skrýt master_key a chránit ho před manipulací. XChaCha20-Poly1305 jej zašifruje pomocí wrapping_key a přidá ověřovací značku. Značka váže šifrovaný text k veřejné hlavičce: nesprávné heslo nebo změna chráněných bajtů způsobí selhání otevření. Značka a náhodná hodnota na jedno použití, nonce, jsou uloženy se šifrovaným textem.

Pokaždé, když je zámek vytvořen nebo znovu zašifrován, aplikace získá novou sůl a nonce. Šifrovaný obsah zahrnuje jeden bajt verze a 32 bajtů master_key; vedle nich je uložen 24bajtový nonce a 16bajtový tag. Konstrukce popisuje dokumentace algoritmu.

Nesoulad mezi obnovenými klíči může být důsledkem úmyslně poškozeného zámku nebo chyby v programu, který jej vytvořil. Náhodné poškození bajtů je obvykle detekováno dříve, když je značka zkontrolována.

Server nemá tajná tajemství potřebná ke kontrole této značky. Pro přenos zámku proto aplikace přidá podpis vytvořený pomocí signing_key. Pokrývá celý hotový soubor, včetně veřejné hlavičky a šifrovaného obsahu. Server zkontroluje podpis a při prvním nahrání připne celou veřejnou část signing_key a interní identifikátor vaultu. Kontroluje následné změny podle tohoto klíče. Zámek a šifrovaná data jsou podepsána stejným signing_key, obnoveným z master_key.

Trezor

Nyní můžeme zámek zveřejnit. Pouze někdo, kdo zná secret_key a master password, může číst master_key, zatímco kdokoli může vzít veřejný podpisový klíč ze souboru zámku a zkontrolovat podepsaná data, aniž by viděl obsah zámku nebo dat.

Zvažte heslo, SuperPa55worD. Zatím to chceme pouze uložit: po zavření aplikace bychom měli být schopni poslat soubor zámku a zašifrované heslo kamkoli, aniž by někdo viděl SuperPa55worD, a přitom jim stále nechat ověřit naše autorství. Šifrování musí být reverzibilní, když máme secret_key a master password. Symetrická šifra může šifrovat a dešifrovat pomocí stejného klíče. Protože tento klíč neukládáme, musíme být schopni jej obnovit pomocí zámku. Budeme tomu říkat message_key.

Pro každé nové šifrování obdržíme samostatné message_key. Ještě musíme zařídit jeho obnovu: ponechání klíče otevřeného vedle šifrovaného textu umožní komukoli, kdo má kopii, aby si vše přečetl.

Z čerstvých náhodných bajtů aplikace vytvoří dočasný pár X25519 pouze pro toto šifrování: record_key. Poté vezme soukromou část record_key a trvalý veřejný klíč trezoru, secret_key, a vypočítá sdílené tajemství. Z tohoto tajemství odvozuje message_key samostatná funkce; tento klíč zašifruje naše heslo.

Při čtení se aplikace vydá jinou cestou. Používá master_key a veřejnou část record_key. Tyto dva klíče vytvářejí stejné sdílené tajemství. Matematicky obě trasy násobí stejný počáteční bod na křivce dvěma soukromými čísly v jiném pořadí. Pořadí nemění výsledek. Můžeme tedy obnovit dešifrovací klíč, aniž bychom ponechali soukromou část record_key.

Získat toto tajemství ze dvou veřejných klíčů je prakticky nemožné: každá cesta potřebuje odpovídající soukromý klíč. Veřejné body nám neumožňují efektivně obnovit soukromá čísla, která je vytvořila. Tento matematický trik podporuje bezpečnost trezoru. Ale to nebrání tomu, aby nám někdo dal jiný trezor s naším zámkem.

Nyní můžeme uložit šifrovaný text vedle veřejné části record_key. Soukromá část record_key a použitá message_key již nejsou pro budoucí čtení potřeba. Později aplikace obnoví dešifrovací klíč z master_key a uloženou veřejnou část record_key. Jedno trvalé tajemství vaultu tak může dešifrovat mnoho samostatně zašifrovaných hodnot, z nichž každá má své vlastní message_key obnovené v případě potřeby.

Skrytí textu nestačí: musíme také detekovat manipulaci při jeho čtení. Šifrování proto přidává autentizační značku, krátkou hodnotu kontrolovanou společně se zašifrovanými daty. Pokud se kontrola nezdaří, aplikace výsledek odmítne. Nesmí zobrazovat náhodný nebo pozměněný text jako úspěšně dešifrované heslo.

public bytes Fresh random bytes record_key secret_key Shared secret Derive message key message_key Encrypted passwordpacket public bytes Fresh random bytes record_key secret_key Shared secret Derive message key message_key Encrypted passwordpacket
Nový pár klíčů pro každé šifrování.

Popsali jsme konstrukci, ve které asymetrický pár pomáhá vytvořit sdílené tajemství, zatímco message_key šifruje obsah. To se nazývá Hybrid Public Key Encryption nebo HPKE a je specifikováno v RFC 9180. Confidex používá X25519 k odsouhlasení tajemství, HKDF-SHA256 k odvození klíčů a ChaCha20-Poly1305 k šifrování s kontrolou integrity. Zde HKDF vezme sdílené tajemství dohodnuté pomocí record_key a dvojice master_key; toto je samostatná úloha od odvození Ed25519 seed. RFC 5869 popisuje HKDF.

Pro další šifrování aplikace vytvoří nový kontext record_key a nový HPKE. Opětovné použití kombinace message_key a nonce prolomí ochranu šifry. V Confidex jsou klíč a nonce odvozeny uvnitř HPKE, použity pro jednu zprávu, a pak je kontext zahozen.

Samotný ChaCha20 používá 256bitový message_key. Abyste získali pocit přímého útoku, představte si fiktivní superpočítač testující miliardu miliard kandidátů za sekundu. Hledání 2²⁵⁶ možných klíčů by trvalo asi 1,8 × 10⁵¹ let. RFC 8439 popisuje algoritmus a jeho analýzu.

Záznam

Jsme šťastní?

Pulp Fiction

Heslo máme uložené, ale přihlášení na web obvykle vyžaduje také uživatelské jméno a adresu. Někdy vedle nich potřebujeme poznámku. Pokud tyto hodnoty ukládáme odděleně, musí si aplikace nějak pamatovat, že k sobě patří. Vložme tyto „papíry“ do obálky. Spojujeme pole do jedné kolekce a nazýváme ji record.

Záznam může obsahovat libovolnou kombinaci polí. Aplikace je sestaví do jednoho paketu, zkomprimuje a celé zašifruje pomocí konstrukce, kterou jsme právě popsali. Hodnoty polí, názvy, typy a značky jsou chráněny. Změnou adresy webu, i když si ponecháte stejné heslo, se vytvoří nová verze celého záznamu, zašifrovaná novým record_key.

Hash-chain

MĚL BY VÁŠ PROJEKT POUŽÍVAT BLOCKCHAIN? → NE

XKCD 2267

Někdo, kdo zná secret_key, může připravit zašifrovaný záznam pro náš trezor. Aby aplikace nepřijímala jako naše, každou verzi záznamu podepisuje signing_key. Bez tohoto klíče nemůže cizí osoba vytvořit verzi s podpisem, kterou server a další zařízení přijmou.

Šifrovaná verze potřebuje nějaké doprovodné informace: ke kterému trezoru a záznamu patří, kdy se změnila a které verze jí předcházejí. Toto tvoří veřejnou hlavičku. Neobsahuje heslo, ale přesto potřebuje ochranu: jinak by někdo mohl změnit vlastnictví a vztahy objektů, aniž by se dotkl šifrovaného textu. Aplikace podepisuje přesné bajty záhlaví spolu se šifrovaným textem. Změna podepsaných dat zneplatní podpis.

Server připomíná skladiště zapečetěných balíků. Vidí hlavičku, zašifrovaný obsah a podpis, ale uvnitř ne heslo, a ví, že příjemce ve městě existuje. Zkontroluje podpis proti připnuté veřejné části signing_key a rozhodne, zda přijme novou verzi. Nepotřebuje ani hlavní heslo, ani secret_key ani žádný soukromý klíč. Při čtení klient zkontroluje stejný podpis a poté znovu zkontroluje vazbu mezi obsahem a hlavičkou během dešifrování pomocí autentizační značky HPKE.

Podpis také chrání odkazy mezi verzemi. SHA-256 hash přesného záhlaví a bajtů šifrovaného textu se stane identifikátorem verze. Záhlaví další verze obsahuje identifikátor předchozí verze. Když změníme heslo webu, aplikace vytvoří a podepíše nový objekt s tímto odkazem. Starý objekt a jeho podpis zůstávají nezměněny. Nahrazení předchůdce při zachování podpisu nové verze proto selže. Pokud dvě zařízení provedou nezávislé změny, přežijí obě větve; sloučená verze může odkazovat na obojí.

Pamatujete si blockchain? Tady to je :-).

Veřejné záhlaví nám umožňuje kontrolovat odkazy bez dešifrování, ale některé informace zůstávají viditelné. Server zná identifikátory, odkazy na verze, čas změny dodaný klientem, počet polí a zakódovanou velikost každé hodnoty pole. Šifrování skryje obsah záznamu, nikoli tyto strukturální informace.

Header andparent IDs Encrypted recordpacket Sign revision signing_key Signed revision Header andparent IDs Encrypted recordpacket Sign revision signing_key Signed revision
Záhlaví a šifrový text jsou podepsány společně.

Synchronizace

„Není to únik dat, ale bezplatná distribuovaná záloha.“

Internetový meme.

Abychom mohli pracovat na několika zařízeních, musíme mezi nimi přenést zámek a nahrávat historii. Formát objektu se nemění: přenášíme stejné zašifrované bajty a podpisy, které jsou uloženy lokálně.

Pro ruční přenos vytvoří aplikace archiv ZIP obsahující zámek, všechny lokálně uložené šifrované verze záznamů a seznam podepsaných souborů. Není zahrnuto heslo ani secret_key. Na jiném zařízení aplikace nejprve otevře zámek, poté zkontroluje podpisy, dešifruje záznamy a obnoví místní kopii trezoru. Import je určen pro zařízení, kde tento trezor ještě neexistuje; neslučuje historii s existující kopií.

Synchronizační server vyměňuje změny mezi pracovními kopiemi. Při prvním nahrání obdrží podepsaný zámek, zkontroluje podpis a vypočítá adresu veřejného trezoru z veřejné části signing_key. Poté si pamatuje tento klíč a identifikátor vaultu z hlavičky: tím se vault zaregistruje na serveru. Následné změny musí odpovídat tomuto identifikátoru a nést podpis ze stejného klíče.

Nové zařízení potřebuje adresu trezoru a secret_key, takže je aplikace zkombinuje do přenosového kódu s kontrolním součtem. Uživatel přenese tento kód do zařízení a samostatně zadá hlavní heslo; na server je odeslána pouze veřejná adresa.

Po otevření staženého zámku aplikace porovná veřejné části obnovených klíčů s secret_key a hlavičkou a porovná vypočítanou adresu s kódem přenosu. Poté uloží ověřenou veřejnou část signing_key ke kontrole záznamů.

Během synchronizace aplikace načte chybějící verze a nahraje své změny. Server kontroluje podpisy a odkazy na předchozí verze, ukládá přijaté objekty a předává je dalším zařízením. Kontrola přijatých dat, jejich dešifrování a řešení konfliktů – to vše probíhá na zařízeních uživatele.

Registrace nevyžaduje žádné jméno, e-mailovou adresu ani samostatné heslo. Server vidí veřejnou adresu, klíč pro ověření podpisu, veřejné hlavičky, velikosti objektů a odkazy na verzi. Vidí také IP adresy a časy požadavků. Hlavní heslo, secret_key, soukromé klíče a obsah záznamu ve formátu prostého textu zůstávají na zařízeních uživatele. Každý, kdo zná veřejnou adresu, si může stáhnout zašifrované objekty, ale jejich čtení vyžaduje tajemství uživatele.

Tyto kontroly detekují padělané předměty, ale neprokazují, že server ukázal kompletní historii a její nejnovější stav. Může skrýt větev, kterou klient nikdy neviděl, nebo vrátit konzistentní starší datovou sadu. Podpis potvrzuje pravost jednotlivého objektu, nikoli úplnost odpovědi serveru. Uživatel si může všimnout chybějících změn na jiném zařízení, ale konzistentní stará historie projde ověřením hash-chain.

Změna hlavního hesla

Takže, chtěla by vaše svatost změnit její heslo?

Hackeři (1995)

Změna hlavního hesla znovu zašifruje pouze zámek; master_key uvnitř zůstává stejné. Záznamy, jejich podpisy, secret_key a adresa trezoru proto zůstávají nezměněny. Nový zámek je podepsán stejným signing_key.

Stará kopie zámku se stále otevře se starým heslem a stejným secret_key; změna hesla neodvolá klíče, které již byly vystaveny.

Úplný obrázek

Zámek chrání master_key, message_key šifruje záznamy a signing_key vytváří podpisy. ZIP archivy a server obdrží zašifrované objekty s podpisy.

public bytes public bytes public bytes master_key Fresh randombytes secret_key record_key Master password wrapping_key signing_key message_key lock Encrypted records Signed lockand records Signatureverification ZIP archive /sync server public bytes public bytes public bytes master_key Fresh randombytes secret_key record_key Master password wrapping_key signing_key message_key lock Encrypted records Signed lockand records Signatureverification ZIP archive /sync server
Klíče, co chrání a co lze sdílet.