Kryptografie, kódování dat
Kryptografie, neboli šifrování dat, je nauka o transformování dat do podoby, která je čitelná jenom s určitou znalostí. Slovo Kryptografie pochází z řečtiny – kryptós (je skrytý) a gráphein (psát).
Pojem kryptografie
Na úvod si řekneme něco o pojmu kryptografie:
Kryptografie, neboli šifrování dat, je nauka o transformování dat do podoby, která je čitelná jenom s určitou znalostí. Slovo Kryptografie pochází z řečtiny – kryptós (je skrytý) a gráphein (psát).
Často je pojem zaměňován, nebo používán, pro vědu o šifrách – kryptologii.
Kryptografie se vyvíjí již celá staletí, nebo tisíciletí. V historii postupně vznikali lepší a důmyslnější šifry, které často ovlivnili mnohé historické události (zejména jednalo li se o utajování a vyzrazování informací).
Taková jednoduchá šifra by mohla vypadat takto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$abeceda = 'abcdefghijklmnopqrstuvwxyz'; function sifra_k($str, $posunuti) { global $abeceda; $str = strtolower($str); for($i = 0; $i < strlen($str); $i++) { $new_pos = strpos($abeceda, $str[$i]) + intval($posunuti); if($new_pos >= ($len = strlen($abeceda))){ $new_pos = $new_pos - $len; } $new_str .= $abeceda[$new_pos]; } return $new_str; } print $string = sifra_k("TotoJeMojeSifrovanaZprava", 4); |
kde jsme jenom posunuli znaky v abecedě. Nicméně na výstupu dostaneme řetězec
xsxsniqsniwmjvszeredtveze, který se zdrojové zprávě nepodobá ani přinejmenším.
Takový je význam šifer a šifrování.
V PHP se kódování využívá nejčastěji pro zakódování informací, které chceme ochránit (například platy zaměstnanců, a podobné citlivé informace), ale může se používat i například pro generování kontrolních součtů souborů.
Použití kódování dat nám zajišťuje vyšší bezpečnost, ale může způsobit i pocit falešného bezpečí, takže na to musíme dávat pozor.
Většina funkcí pro kódování dat je v knihovnách mcrypt a mhash.
Kódování
Ve své podstatě existují dva druhy kódování: asymetrický (s veřejným klíčem) a symetrické (s tajným klíčem).
- symetrická kryptografie: při symetrickém kódování je potřeba tzv. klíče. Klíč je určitá hodnota (informace), podle niž dojde k zakódování textu. V příkladu, který zde byl uveden, je takový klíč číslo 4. Klíč může být ovšem i větších rozměrů: 4 -> 6 -> 2. Volání by potom vypadalo takto:
1 2 3 4 |
$string = sifra_k("TotoJeMojeSifrovanaZprava", 4); $string = sifra_k($string, 4); $string = sifra_k($string, 4); print $string = sifra_k($string, 4); |
- pokud chceme potom text rozkódovat, potřebujeme stejný klíč a výsledný zašifrovaný řetězec. Jinak bychom neměli být schopni z šifrovaného textu dostat zdrojový text. Výhodou tohoto šifrování je její rychlost a využívá se pro šifrování dat, která již dále neputují, například dokumenty na svém počítači. Jako nevýhodu můžeme uvést klíč, který je potřeba pro výměnu takových informací.
Pokud bychom chtěli s někým komunikovat, musíme mu nějak sdělit náš klíč. - asymetrická kryptografie: asymetrická kryptografie se od symetrické liší právě použitím klíčů. Používá totiž jeden klíč pro zašifrování a jiný klíč pro dešifrování. Takové dva klíče se nazývají keypair. Klíč pomocí něhož se šifruje se potom nazývá veřejný (public) klíč a klíči pro dešifrování říkáme soukromý (private) klíč. Při práci máme k dispozici dva klíče, přičemž veřejný klíč znají všichni, kdo s námi chtějí tajně komunikovat a soukromý klíč znáte jenom vy. Tím pádem odpadá problém při předávání klíče, ale můžeme jej v klidu rozesílat internetem. Útočník, který by jej odchytil by získal jenom veřejná všude známý klíč, který by mu k ničemu nebyl.
Pokud tedy budete chtít využívat šifrování v PHP, budete potřebovat knihovnu mcrypt nebo mhash. Tyto dvě knihovny obsahují celou spoustu algoritmů, ze kterých si můžete vybrat pro vás ten nejlepší. Uvedu příklad z knihovny mcrypt.
- MCRYPT_3DES
- MCRYPT_DES
- MCRYPT_TripleDES
- MCRYPT_ENIGMA
- MCRYPT_IDEA
- MCRYPT_RIJNDAEL_256
- MCRYPT_RC6
- MCRYPT_SAFER128
- MCRYPT_SERPENT_256
- MCRYPT_THREEWAY
- MCRYPT_TWOFISH256
a mnohé další.
Bohužel mnohé z těchto algoritmů nejsou dostatečně bezpečné, proto je důležité si správně vybrat. Míra zabezpečení závisí taky na velikosti klíče, který je použit. Uvědomte si, že klíč o velikosti 43 bitů je dvakrát tak účinný a trvalo by dvojnásobnou dobu jej prolomit útokem typu Brute Force (klíč má dvojnásobný počet kombinací) než klíč s velikostí 42 bitů.
V PHP má kódování uplatnění hlavně při předávání informací, ať už mezi serverem a klientem, nebo mezi servery. Míra důležitosti informace by se neměla podceňovat.
K použití algoritmů můžete zase využít funkci mcrypt. Před použitím musíte ovšem znát algoritmus kódování, který chcete použít, režim, ve kterém chcete kódovat, a konstantu, která udává co chcete s daným řetězcem dělat.
Jako algoritmus uvádíme název algoritmu uvedený v knihovně mcrypt.
Režim, je způsob, který se bude brát v ohled při kódování. U funkce mcrypt můžete použít několik různých režimů:
- EBC: tento režim se používá nejčastěji pro kódování malých objemů dat. Tento způsob ale není moc bezpečný.
- CBC: univerzální režim. Používá se pro kódování jak malých dat, tak i větších souborů. Je mnohem bezpečnější než EBC.
- CBF: pro datové bitové proudy.
- OFB: režim je podobný režimu CBF, ale může být použita v aplikacích, kde nesmí být tolerovány chyby.
- NOFB: je režim podobný OFB, ale je bezpečnější.
- STREAM: je speciální režim.
Pokud jde o konstanty, na výběr máte z pěti různých:
- MCRYPT_ENCRYPT
- MCRYPT_DECRYPT
- MCRYPT_DEV_RANDOM
- MCRYPT_DEV_UNRANDOM
- MCRYPT_RAND
Každá z nic má jiné využití.
A výsledná funkce může vypadat takto:
1 2 |
$data = "data pro zakodovani."; print $kodovana_data = mcrypt_ecb(MCRYPT_TRIPLEDES, "klic", $data, MCRYPT_ENCRYPT); |
Pokud tento skript spustíme, dostaneme jenom směsici nesmyslných znaků, které nedávání smysl. Jsou to binární data, které funkce mcrypt vrací. Pro normální použítí, například í v SESSION, nebo COOKIES proměnných je ovšem potřeba data ještě upravit a nepoužívat jejich binární podobu. Můžeme použít funkci bin2hex, nebo klidně třeba funkci urlencode, abychom převedli binární znaky do podoby, kterou je schopen server zpracovávat a předávat.
1 |
print bin2hex($kodovana_data); |
Pro dekódování tímto způsobem musíme použít stejný režim jako pro kódování, ale s konstantou MCRYPT_DECRYPT:
1 2 |
$kodovana_data = mcrypt_ecb(MCRYPT_TRIPLEDES, "klic", $kodovana_data, MCRYPT_DECRYPT); print $kodovana_data; |
Podle nastavení serveru můžete dostat na výstupu warning:
1 2 3 4 |
<b>Warning:</b> mcrypt_ecb() [<a href="#" onclick="return false;">function.mcrypt-ecb</a>]: Attempt to use an empty IV, which is NOT recommend in <b>/home/www/zaachi.com/subdomains/pokus/index.php</b> on line <b>4</b> |
Parser vás varuje, že jste použili prázdný Inicializační Vektor (IV), což nedoporučuje.
Inicializační vektor se generuje z určitých vstupních dat a pokud nemá druhá strana stejný inicializační vektor, nemělo by se jí podařit data dekódovat, takže se jedná o další možné zabezpečení.
Pokud bychom chtěli vytvořit skript pro kódování s inicializačním vektorem, mohl by vypadat nějak takto:
Vytvoříme třídu, která se bude používat jak pro kódování, tak dekódování:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
class crypt_str { public $key = NULL; public $algoritmus = NULL; public $rezim = NULL; function __construct($key, $algoritmus = 'des', $rezim = 'cbc'){ if(($this->key = $key) == NULL) return 0; $this->algoritmus = $algoritmus; $this->rezim = $rezim; } function hash_key(){ $this->key = sha1($this->key); } function encrypt($string,$key) { //nejprve otevřeme modul algoritmu pro jeho použití //parametry: algoritmus, knihovna algoritmu, režim, knihovna režimu $moopen = mcrypt_module_open($this->algoritmus, '',$this->rezim, ''); //funkce mcrypt_enc_get_key_size vrátí maximální podporovanou délku klíče //nastavíme tedy klíč na jeho maximální možnou velikost $this->key = substr($this->key, 0, mcrypt_enc_get_key_size($moopen)); //nastavíme velikost IV (inicializační vektor) $iv_size = mcrypt_enc_get_iv_size($moopen); //a vytvoříme inicializační vektor - IV //MCRYPT_DEV_RANDOM čte nádohná data z dev/random $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_RANDOM); //inicializujeme všechny buffery potřebné pro encription if (mcrypt_generic_init($moopen, $this->key, $iv) != -1) { //závisle na algoritmu kódujeme data $c_str = mcrypt_generic($moopen, $string); //deinicializujeme všechny buffery mcrypt_generic_deinit($moopen); //uzavřeme modul mcrypt_module_close($moopen); $c_str = $iv.$c_str; //vrátíme řetězec v binárním tvaru. return $c_str; } else return -1; } function decrypt($string,$key) { //zase nejprve otevřeme modul $moopen = mcrypt_module_open($this->algoritmus, '',$this->rezim, ''); //vytvoříme maximálně velký klíč pro použitý algoritmus $this->key = substr($this->key, 0, mcrypt_enc_get_key_size($moopen)); //nastavíme velikost IV $iv_size = mcrypt_enc_get_iv_size($moopen); //musíme nastavit IV na maximální velikost $iv = substr($string,0,$iv_size); //z řetězce vrátíme pouze jenom maximální velikost $string = substr($string,$iv_size); //inicializujeme buffers if (mcrypt_generic_init($moopen, $this->key, $iv) != -1) { //decryptujeme data závisle na modulu $c_str = mdecrypt_generic($moopen, $string); //deinicializujeme buffers mcrypt_generic_deinit($moopen); //uzavřeme modul mcrypt_module_close($moopen); return $c_str; } else return -1; } } |
Ve volání konstruktoru se nejprve nastaví hodnoty jako je: režim kódování, algoritmus, pomocí něhož se kóduje a potřebný klíč.
Po vytvoření nové instance třídy můžeme ještě vytvořit hash klíče, pro větší bezpečnost, a zavolat příslušnou obslužnou funkci, přičemž máme na výběr ze dvou: encrypt (pro zakódování) a decrypt (pro dekódování).
Takové volání potom může vypadat následovně:
1 2 3 4 5 6 7 8 9 |
$data = "Data pro zakódování"; $key = "klic"; //vytvoříme novou instanci třídy $use = new crypt_str("klic"); //pro větši bezpečnost můžeme vytvořit hash klíče $use->hash_key(); //a pro ověření spustíme: print $use->decrypt($use->encrypt($data, $key), $key); |
Bohužel na některých serverech nemusí fungovat konstanta MCRYPT_DEV_RANDOM, ale budete ji muset nahradit konstantou MCRYPT_RAND. Před jejím použitím musíte ale nastartovat generátor náhodných čísel:
1 |
srand((double) microtime() * 1000000); |
a při vytváření inicializačního vektoru je nutno nahradit konstantu MCRYPT_DEV_RANDOM konstantou MCRYPT_RAND:
1 |
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); |
Je nutné si uvědomit, že pokud má útočník přístup na server, má přístup i k vašemu klíči. Pokud tedy vytváříte inicializační vektor, pak mu alespoň přiděláte trochu práce.
Pokud chcete svá data opravdu zabezpečit tak aby se k nim opravdu nikdo nedostal, pak vám nezůstane žádná jiná možnost, než používat vlastní server, ke kterému nemá kromě vás nikdo jiný přístup, nebo data nevystavovat na internetu. Až pak budou data možná v bezpečí. Pokud budete využívat cizí hosting, nemůžete mít nikdy stoprocentní jistotu, že vaše data nikdo nečte.