Last active
April 8, 2025 14:02
-
-
Save ridercz/37bcc450afe7c395abb6d60176982491 to your computer and use it in GitHub Desktop.
Hashovací algoritmy nejenom v .NET
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"polyglot_notebook": { | |
"kernelName": "csharp" | |
} | |
}, | |
"source": [ | |
"# Hashovací algoritmy nejen v .NET\n", | |
"\n", | |
"[Video na YouTube](https://youtu.be/qpagSLYgOqg)\n", | |
"\n", | |
"Hashovací (_hešovací_) algoritmy jsou důležité nejenom pro počítačovou bezpečnost, ale i mimo ni. Používají se všude tam, kde je nutné jednoduše ověřit shodu dat a nechceme nebo nemůžeme porovnávat data samotná.\n", | |
"\n", | |
"Jedná se o matematické algoritmy, které dokáží z libovolných vstupních dat vytvořit hash (otisk, thumbprint, fingerprint, kontrolní součet...), který:\n", | |
"\n", | |
"* Má fixní délku, danou konstrukcí hashovacího algoritmu, bez ohledu na délku vstupních dat.\n", | |
"* Je pro stejná data vždy stejný.\n", | |
"* Neumožňuje zpětné odvození původních dat\n", | |
"\n", | |
"## Typické hashovací algoritmy\n", | |
"\n", | |
"* **[MD5](https://en.wikipedia.org/wiki/MD5)** (128 bitů), **[SHA-1](https://en.wikipedia.org/wiki/SHA-1)** (160 bitů) - zastaralé, dnes se již nehodí pro většinu kryptografických účelů, ale pořád mají své využití.\n", | |
"* **[SHA-2](https://en.wikipedia.org/wiki/SHA-2)** - rodina hashovacích algoritmů, zahrnuje SHA-256, SHA-384, SHA-512. Dnes nejrozšířenější.\n", | |
"* **[SHA-3](https://en.wikipedia.org/wiki/SHA-3)** - nejnovější standard, zahrnuje SHA3-256, SHA3-384, SHA3-512. Není ještě dostupný všude, **v .NETu zatím podporován jenom na některých platformách.**" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"\n", | |
"## Použití v .NETu\n", | |
"\n", | |
"Hashovací algoritmy žijí v namespace `System.Security.Cryptography`. Na MD5 si můžeme ukázat typické vlastnosti:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": { | |
"polyglot_notebook": { | |
"kernelName": "csharp" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"MD5(AHOJ) = 5d75193725cfb92ce9aee96b5380db06\n", | |
"MD5(AHOK) = e1f33a0b79e18cbe326c8b1d532377f7\n", | |
"MD5(DLOUHÝTEXT) = 59ce7f82ebede9fbba1f1c002a3a79e3\n" | |
] | |
} | |
], | |
"source": [ | |
"using System.Security.Cryptography;\n", | |
"\n", | |
"static string HashMD5(string s) {\n", | |
" // Hashovací funkce pracují s polem bajtů, proto je potřeba převést string na pole bajtů\n", | |
" byte[] data = System.Text.Encoding.UTF8.GetBytes(s);\n", | |
" \n", | |
" // Vytvoříme instanci MD5 hashovací funkce\n", | |
" var hash = MD5.Create();\n", | |
"\n", | |
" // Vypočítáme hash\n", | |
" byte[] hashData = hash.ComputeHash(data);\n", | |
"\n", | |
" // Převedeme bajty na hexadecimální string\n", | |
" return string.Join(string.Empty, hashData.Select(b => b.ToString(\"x2\")));\n", | |
"}\n", | |
"\n", | |
"// Příklad použití\n", | |
"Console.WriteLine(\"MD5(AHOJ) = \" + HashMD5(\"AHOJ\"));\n", | |
"Console.WriteLine(\"MD5(AHOK) = \" + HashMD5(\"AHOK\"));\n", | |
"Console.WriteLine(\"MD5(DLOUHÝTEXT) = \" + HashMD5(\"DLOUHÝTEXT\"));" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Všechny hashovací algoritmy jsou poděděné od bázové třídy `HashAlgorithm`, takže můžeme napsat generickou metodu pro hashování:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": { | |
"polyglot_notebook": { | |
"kernelName": "csharp" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"MD5(AHOJ) = 5d75193725cfb92ce9aee96b5380db06\n", | |
"SHA-1(AHOJ) = abeb42a478401e2897b9deb1acfcfda5614522ae\n", | |
"SHA-256(AHOJ) = eadf084bdc2901bd5b9a5399e60767289e4da3c60a60833a87fd3c96dfbf76e1\n", | |
"SHA-384(AHOJ) = ac6527d57f755be2986bc0f1c40576be56c57d32da0ee341a02791932be6cbf7d83b328ed76bbbfea6fae710c800be89\n", | |
"SHA-512(AHOJ) = 8849b59816ba95d4c281a00665b9ff58b3574ec271bdcca71360446215a2df281359d0bfcc1670fce68f6aaafb4ddac21c5ccb80104f484e82ee599a1b011c4e\n" | |
] | |
}, | |
{ | |
"ename": "Error", | |
"evalue": "System.PlatformNotSupportedException: Operation is not supported on this platform.\r\n at System.Security.Cryptography.SHA3_256.Create()\r\n at Submission#7.<<Initialize>>d__0.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)", | |
"output_type": "error", | |
"traceback": [ | |
"System.PlatformNotSupportedException: Operation is not supported on this platform.\r\n", | |
" at System.Security.Cryptography.SHA3_256.Create()\r\n", | |
" at Submission#7.<<Initialize>>d__0.MoveNext()\r\n", | |
"--- End of stack trace from previous location ---\r\n", | |
" at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)" | |
] | |
} | |
], | |
"source": [ | |
"static string Hash(string s, HashAlgorithm hash) {\n", | |
" // Hashovací funkce pracují s polem bajtů, proto je potřeba převést string na pole bajtů\n", | |
" byte[] data = System.Text.Encoding.UTF8.GetBytes(s);\n", | |
" // Vypočítáme hash\n", | |
" var hashData = hash.ComputeHash(data);\n", | |
"\n", | |
" // Převedeme bajty na hexadecimální string\n", | |
" return string.Join(string.Empty, hashData.Select(b => b.ToString(\"x2\")));\n", | |
"}\n", | |
"\n", | |
"// Příklad použití\n", | |
"\n", | |
"Console.WriteLine(\"MD5(AHOJ) = \" + Hash(\"AHOJ\", MD5.Create()));\n", | |
"Console.WriteLine(\"SHA-1(AHOJ) = \" + Hash(\"AHOJ\", SHA1.Create()));\n", | |
"Console.WriteLine(\"SHA-256(AHOJ) = \" + Hash(\"AHOJ\", SHA256.Create()));\n", | |
"Console.WriteLine(\"SHA-384(AHOJ) = \" + Hash(\"AHOJ\", SHA384.Create()));\n", | |
"Console.WriteLine(\"SHA-512(AHOJ) = \" + Hash(\"AHOJ\", SHA512.Create()));\n", | |
"Console.WriteLine(\"SHA3-256(AHOJ) = \" + Hash(\"AHOJ\", SHA3_256.Create()));\n", | |
"Console.WriteLine(\"SHA3-384(AHOJ) = \" + Hash(\"AHOJ\", SHA3_384.Create()));\n", | |
"Console.WriteLine(\"SHA3-512(AHOJ) = \" + Hash(\"AHOJ\", SHA3_512.Create()));" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Tento kód předpokládá, že data jsou dostatečně malá na to, abychom je udrželi v paměti najednou. Pokud tomu tak není, lze použít jako vstup `Stream`. Je nutné počítat s tím, že u objemnějších dat bude výpočet hashe nějakou dobu trvat." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": { | |
"polyglot_notebook": { | |
"kernelName": "csharp" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Hash | Čas | Hash\n", | |
"------------------------------------------------------------------------------------------------------------------------------------------------------\n", | |
"MD5 | 1497 ms | bcf84c500cd661e95bea8eebd7fbcd1b\n", | |
"SHA-1 | 1347 ms | 0570a2a468771efa8492cf3d74e8eefa5fc929c9\n", | |
"SHA-256 | 759 ms | e8c7cf1f4ad1a52895c99338d100d5a9c0ad6d51a6f76230e095d6f657683d65\n", | |
"SHA-384 | 1610 ms | c508cb2a75978c19dc826d5ad2c7e959078d603e2f511f8f9fdec8552b260f03c1492ec3baff663f011d92b7c632fb1a\n", | |
"SHA-512 | 1638 ms | 292431b2f3e8d97da2dfccac2e069609dbbc3e4fee43d928cb1ac903fab3b31c09567f6d0294aa677385637b71e5b40a6cfe42261a176d5a63fbd4900597d3d8\n", | |
"------------------------------------------------------------------------------------------------------------------------------------------------------\n", | |
"Velikost souboru D:\\Install\\SQL_Server_2022_Express_Advanced.iso je 623 MB\n" | |
] | |
} | |
], | |
"source": [ | |
"using System.IO;\n", | |
"using System.Diagnostics;\n", | |
"\n", | |
"static (string, TimeSpan) HashStream(Stream s, HashAlgorithm hash) {\n", | |
" // Vypočítáme hash a změříme čas\n", | |
" Stopwatch sw = Stopwatch.StartNew();\n", | |
" byte[] hashData = hash.ComputeHash(s);\n", | |
" sw.Stop();\n", | |
"\n", | |
" // Převedeme bajty na hexadecimální string\n", | |
" var hashString = string.Join(string.Empty, hashData.Select(b => b.ToString(\"x2\")));\n", | |
" return (hashString, sw.Elapsed);\n", | |
"}\n", | |
"\n", | |
"static void HashFile(string label, string fileName, HashAlgorithm hash) {\n", | |
" using var fs = File.OpenRead(fileName);\n", | |
" var (hashString, time) = HashStream(fs, hash);\n", | |
" Console.WriteLine($\"{label,-8} | {time.TotalMilliseconds,4:F0} ms | {hashString}\");\n", | |
"}\n", | |
"\n", | |
"const string FileName = @\"D:\\Install\\SQL_Server_2022_Express_Advanced.iso\";\n", | |
"\n", | |
"Console.WriteLine($\"{\"Hash\",-8} | {\"Čas\",-7} | Hash\");\n", | |
"Console.WriteLine(new string('-', 150));\n", | |
"HashFile(\"MD5\", FileName, MD5.Create());\n", | |
"HashFile(\"SHA-1\", FileName, SHA1.Create());\n", | |
"HashFile(\"SHA-256\", FileName, SHA256.Create());\n", | |
"HashFile(\"SHA-384\", FileName, SHA384.Create());\n", | |
"HashFile(\"SHA-512\", FileName, SHA512.Create());\n", | |
"//HashFile(\"SHA3-256\", FileName, SHA3_256.Create());\n", | |
"//HashFile(\"SHA3-384\", FileName, SHA3_384.Create());\n", | |
"//HashFile(\"SHA3-512\", FileName, SHA3_512.Create());\n", | |
"Console.WriteLine(new string('-', 150));\n", | |
"Console.WriteLine($\"Velikost souboru {FileName} je {new FileInfo(FileName).Length / 1024 / 1024} MB\");" | |
] | |
}, | |
{ | |
"attachments": { | |
"image.png": { | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA7QAAAD7CAIAAADVQ0/dAAAgAElEQVR4Ae29v45cR6/2O8neO1VgGIo/GI6dKBpdgR36BgxFk/lEzh051ARzD44NSIAu4Evt3AIUvcEOFJxUUnIOyCqSD1l/umfUkkY9zwtj79VrVbHIH1kk1+o16ovXb/7D/0iABEiABEiABEiABEiABF6/+c/F6zf/eff+A/8jARIgARIgARIgARIggQdOgM0x7wpIgARIgARIgARIgARIoBNgc8xQIAESIAESIAESIAESIIFOgM0xQ4EESIAESIAESIAESIAEOgE2xwwFEiABEiABEiABEiABEugE2BwzFEiABEiABEiABEiABEigE2BzzFAgARIgARIgARIgARIggU6AzTFDgQRIgARIgARIgARIgAQ6ATbHDAUSIAESIAESIAESIAES6ATYHDMUSIAESIAESIAESIAESKATYHPMUCABEiABEiABEiABEiCBToDNMUOBBEiABEiABEiABEiABDoBNscMBRIgARIgARIgARIgARLoBNgcMxRIgARIgARIgARIgARIoBNgc8xQIAESIAESIAESIAESIIFOgM0xQ4EESIAESIAESIAESIAEOgE2xwwFEiCBUxL445+3q//evT/lQpRGAiRAAiRAAp+CAJtjVmsSIIFTElh1xn/88/ZTpDDKJAESIAESIIHTEmBzfMq24LS+oTQS+BoJsDn+Gr1GnUmABEiABJwAm2M2xyRAAqckwObY0ysPSIAESIAEvkYCJ2qOX1w9+ubq5ed4ofDVs28eP3sxq+WfT4fZ6p/D9q9n3bPyxZvnl48ffdP+e/r8X/DCvzdP+vnHjy5vXt+3GDiNerLjnly/OT67PbjmWKI9B8Z9i4TPo8/HcXh55busZXjdd1evjg+8NPI0wQ+b/fMw5CokQAL3g8Ana45bbsodw+vrp9ZkPJ6WkzZgW4mPbo4xOaYMu+511i7BxC0mZLtSUi5CQI2tXSfJwgJnCnalIXgEqzsiSvc8mUO6lJYozbF87JXveAiwFurWQcFVUANoP0pO//AOdLgVIllo7u5F17jSAc8rjfk9XomfzUe0qBgrsxbqbQTOL23ktHiLnqY5tzfHf/3+7UX874dr+Su9d+8/gON8YvLvIgngWuDx0LkNSKIkJgG7x95BHVIwxxKLTSqOGNY9OMsH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AiRAAiRAAiRAAp0Am2OGAgmQAAmQAAmQAAmQAAl0AmyOGQokQAIkQAIkQAIkQAIk0AmwOWYokAAJkAAJkAAJkAAJkEAnwOaYoUACJEACJEACJEACJEACnQCbY4YCCZAACZAACZAACZAACXQCbI4ZCiRAAiRAAiRAAiRAAiTQCbA5ZiiQAAmQAAmQAAmQAAmQQCfA5pihQAIkQAIkQAIkQAIkQAKdwMXrN//hfyRAAiRAAiRAAiRAAiRAAq/f/Eea43fvP/A/EiABEiABEiABEiABEnjgBNgc866ABEiABEiABEiABEiABDoBNscMBRIgARIgARIgARIgARLoBNgcMxRIgARIgARIgARIgARIoBNgc8xQIAESIAESIAESIAESIIFOgM0xQ4EESIAESIAESIAESIAEOgE2xwwFEiABEiABEiABEiABEugE2BwzFEiABEiABEiABEiABEigE2BzzFAgARIgARIgARIgARIggU6AzTFDgQRIgARIgARIgARIgAQ6ATbHDAUSIAESIAESIAESIAES6ATYHDMUSIAESIAESIAESIAESKATYHPMUCABEiABEiABEiABEiCBToDNMUOBBEiABEiABEiABEiABDoBNscMBRIgARIgARIgARIgARLoBNgcMxRIgARIgARIgARIgARIoBNgc8xQIAESOCWBP/55u/rv3ftTLkRpJEACJEACJPApCLA5ZrUmARI4JYFVZ/zHP28/RQqjTBIgARIgARI4LQE2x6dsC07rG0ojga+RAJvjr9Fr1JkESIAESMAJsDlmc0wCJHBKAmyOPb3ygARIgARI4GskcKLm+MXVo2+uXn6OFwpfPfvm8bMXs1r++XSYrf45bP961j0rX7x5fvn40Tftv6fP/wUv/HvzpJ9//Ojy5vV9i4HTqCc77sn1m+Oz24NrjiXac2Dct0j4PPp8HIeXV77LWobXfXf16vjASyNPE/yw2T8PQ65CAiRwPwh8sua45abcMby+fmpNxuNpOWkDtpX46OYYk2PKsOteZ+0STNxiQrYrJeUiBNTY2nWSLCxwpmBXGoJHsLojonTPkzmkS2mJ0hzLx175jocAa6FuHRRcBTWA9qPk9A/vQIdbIZKF5u5edI0rHfC80pjf45X42XxEi4qxMmuh3kbg/NJGTou36Gmac605/vOHC/vfd7//pn+l9+79B3CcT0z+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" | |
} | |
}, | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Kolizní zprávy\n", | |
"\n", | |
"Vzhledem k tomu, že množina možných vstupních dat (neomezená délka) je větší než množina možných výstupních dat (fixní délka), logicky musejí existovat tzv. kolizní zprávy (collision messages). Tj. dvoje různá vstupní data, která mají stejný hash. U algoritmů SHA-2 a SHA-3 je (zatím) neumíme najít. U MD5 a SHA-1 už ano.\n", | |
"\n", | |
"Příklad kolizní zprávy ([zdroj](https://en.wikipedia.org/wiki/MD5#Collision_vulnerabilities)):\n", | |
"\n", | |
"" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": { | |
"polyglot_notebook": { | |
"kernelName": "csharp" | |
} | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"MD5(msg1): 79054025255fb1a26e4bc422aef54eb4\n", | |
"MD5(msg2): 79054025255fb1a26e4bc422aef54eb4\n", | |
"msg1 == msg2: False\n" | |
] | |
} | |
], | |
"source": [ | |
"// Stringová reprezentace kolizních zpráv\n", | |
"var msg1string = \"d131dd02c5e6eec4693d9a0698aff95c2fcab58712467eab4004583eb8fb7f8955ad340609f4b30283e488832571415a085125e8f7cdc99fd91dbdf280373c5bd8823e3156348f5bae6dacd436c919c6dd53e2b487da03fd02396306d248cda0e99f33420f577ee8ce54b67080a80d1ec69821bcb6a8839396f9652b6ff72a70\";\n", | |
"var msg2string = \"d131dd02c5e6eec4693d9a0698aff95c2fcab50712467eab4004583eb8fb7f8955ad340609f4b30283e4888325f1415a085125e8f7cdc99fd91dbd7280373c5bd8823e3156348f5bae6dacd436c919c6dd53e23487da03fd02396306d248cda0e99f33420f577ee8ce54b67080280d1ec69821bcb6a8839396f965ab6ff72a70\";\n", | |
"\n", | |
"// Převedeme hexadecimální stringy na pole bajtů\n", | |
"var msg1 = Enumerable.Range(0, msg1string.Length / 2).Select(i => Convert.ToByte(msg1string.Substring(i * 2, 2), 16)).ToArray();\n", | |
"var msg2 = Enumerable.Range(0, msg2string.Length / 2).Select(i => Convert.ToByte(msg2string.Substring(i * 2, 2), 16)).ToArray();\n", | |
"\n", | |
"// Funkce pro výpočet MD5 hashe\n", | |
"static string HashBytesMD5(byte[] data) {\n", | |
" // Vytvoříme instanci MD5 hashovací funkce\n", | |
" var hash = MD5.Create();\n", | |
"\n", | |
" // Vypočítáme hash\n", | |
" byte[] hashData = hash.ComputeHash(data);\n", | |
"\n", | |
" // Převedeme bajty na hexadecimální string\n", | |
" return string.Join(string.Empty, hashData.Select(b => b.ToString(\"x2\")));\n", | |
"}\n", | |
"\n", | |
"// Vypočítáme MD5 hash pro obě zprávy\n", | |
"Console.WriteLine($\"MD5(msg1): {HashBytesMD5(msg1)}\");\n", | |
"Console.WriteLine($\"MD5(msg2): {HashBytesMD5(msg2)}\");\n", | |
"Console.WriteLine($\"msg1 == msg2: {msg1.SequenceEqual(msg2)}\");\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Přesto algoritmy MD5 a SHA-1 nejsou bezcenné a lze je nadále používat, např.:\n", | |
"\n", | |
"* Pro porovnání změněných souborů, kde nepředpokládáme cílený útok. Například Azure Storage a AzCopy využívá MD5, protože má malou délku.\n", | |
"* Při [generování jednorázových hesel](https://www.youtube.com/watch?v=u352xYwSGAs), kde jsou na ně kladeny nižší nároky." | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": ".NET (C#)", | |
"language": "C#", | |
"name": ".net-csharp" | |
}, | |
"polyglot_notebook": { | |
"kernelInfo": { | |
"defaultKernelName": "csharp", | |
"items": [ | |
{ | |
"aliases": [], | |
"languageName": "csharp", | |
"name": "csharp" | |
} | |
] | |
} | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment