neljapäev, 26. november 2015

Jagatud saladused

Kui üldiselt räägitakse krüptograafia puhul kas sümmeetrilisest (andmed krüpteeritakse ja avatakse sama võtmega) või asümmeetrilisest (andmed krüpteeritakse avaliku võtmega, avatakse salajase võtmega) krüptograafiast, siis eksisteerib veel üks põnev andmete krüpteerimise meetod, nimelt jagatud saladuste kasutamine.

Ma ei ole teoreetik, vaid praktik, seega ei oska öelda, et kas see on päris eraldiseisev või hoopis sümmeetrilise krüptograafia erivorm, kuid erinevus tavalisest sümmeetrilisest krüpteerimisest seisneb selles, et andmete avamiseks on vaja mitut võtit. Kusjuures ükski võti omaette ei ütle meile andmete sisust mitte midagi, kuid koos suudavad selle avada. Vaatamegi siin lähemalt üht tuntuimat jagatud saladuste algoritmi Shamir's Secret Sharing (originaalne artikkel, PDF) ja eelkõige siis selleks, et kuidas seda praktikas kasutada.

Shamiri jagatud saladuste algoritmi puhul võime genereerida suvalise n arvu võtmeid, kusjuures saladuse taastamiseks on vaja teada ainult k võtit, kus k võib olla võrdne või väiksem kui n. Seega kui n on näiteks 4 (võtmeteks on S1, S2, S3 ja S4) ja k on 2, siis saladuse avamiseks sobib ükskõik milline järgmistest kombinatsioonidest S1+S2S1+S3S1+S4S2+S3S2+Svõi S3+S4, kus kombinatsioonide arvu leiame valemiga n!/((n-k)!(k!)).

Kus sellist jagatud saladust üldse kasutada? Üheks praktiliseks näiteks võiks olla kahefaktoriline autentimine sellises teenuses, kus kasutaja andmeid krüpteeritakse ja avatakse brauseris mingi sümmeetrilise võtmega. Sümmeetriline võti oleks peidetud Shamiri algoritmiga ning selle avamiseks peaksime teadma vajalikku hulka jagatud võtmeid (meie näiteks 2). Sellisel juhul teaks kasutaja üht jagatud saladuse kahest vajalikust võtmest ja server teaks teist. Kui kasutaja nüüd suudab tõendada serverile teise faktori olemasolu, saadab server kasutajale enda teada oleva saladuse, kasutaja paneb kaks saladust kokku ja saabki võtme oma andmete avamiseks. Me ei saa kasutada Shamiri jagatud saladust otse andmete peitmiseks, kuna see sobib vaid väikese suuruse andmete jaoks, nimelt on jagatud saladuse üksikud osad sama suured kui peidetavad andmed.

Järgmises näites kasutame Shamiri jagatud saladuste JavaScripti implementatsiooni (täpsemalt Node.JS versiooni), mille leiab siit.

Alustuseks on on meil andmed, mida tahame peita ning sümmeetriline parool nende andmete krüpteerimiseks.

var vault = "suur saladus";
var secret = "salakala";

var crypto = require("crypto");
var cipher = crypto.createCipher("aes256", secret);
cipher.update(vault);
var encrypted = cipher.final("hex");

// "2230f86334604f915cca82247378f7c4" -> saadame serverisse

Järgmiseks jagame krüpteerimiseks kasutatud saladuse mitmeks osaks Shamiri jagatud saladuste algoritmiga ja salvestame kuidagi koha peal ja teise poole saadame serverisse.

var secret = "salakala";

var secrets = require("secrets.js");
var shares = secrets.share(new Buffer(secret).toString('hex'), 2, 2);

// "80181920359aa3b26722b" -> salvestame
// "8021caca506eacbef50f5" -> saadame serverisse

Seega server teab nüüd esiteks krüpteeritud andmeid "2230f86334604f915cca82247378f7c4" ning üht osa jagatud saladusest "8021caca506eacbef50f5". Meie aga omakorda teame teist osa jagatud saladusest "80181920359aa3b26722b". Kumbki pool ei saa hetkel nende andmetega suurt midagi peale hakata.

Ütleme, et tahame nüüd uuesti vaadata, et mis need salajased andmed olid. Sellepärast küsime serverist kõigepealt peidetud andmed ja seejärel teeme läbi kahefaktorilise autentimise. Ütleme, et server saadab selle jaoks meile mingi koodiga SMS sõnumi, sisestame sõnumis olnud koodi ja nüüd saadab server meile ka teise osa jagatud saladusest. Seega on meil olemas kõik vajalik, et andmed taastada.

Selleks taastame kõigepealt jagatud saladustest salajase parooli.

var shares = ["80181920359aa3b26722b","8021caca506eacbef50f5"];

var hex = secrets.combine(shares);
var secret = new Buffer(hex, 'hex').toString();

// "salakala

Ja seejärel dekrüpteerime saadud saladusega krüpteeritud andmed.

var encrypted = "2230f86334604f915cca82247378f7c4";
var secret = "salakala";

var decipher = crypto.createDecipher('aes256', secret);
decipher.update(new Buffer(encrypted, 'hex'));
console.log(decipher.final('utf-8'));

// "suur saladus"

Kasutatud näide on muidugi väga lihtsustatud, seega reaalsed lahendused oleks tunduvalt keerukamad. Näiteks võiks jagatud saladused krüpteerida kasutaja parooliga ning mõlemad serverisse saata. Samuti tuleks andmete krüpteerimisel kasutada paremat meetodit, kui vaikimisi seadistuses crypto.createCipher seda on (valida tuleks turvaline initsialiseerimisvektor jne.). Samuti on vaja lahendada mõistlik autoriseerimisprotsess, kus krüpteeritud andmeid saaks laadida ja salvestada ainult õige isik. Need küsimused ei ole samas käesoleva näite puhul väga olulised, kuna eesmärk oli lihtsalt tutvustada jagatud saladuste kontseptsiooni. Mida nende jagatud saladustega peale hakata, on juba igaühe enda välja mõelda.

Kommentaare ei ole: