<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Maciej[cc] &#187; C++</title><atom:link href="https://nabozny.io/tag/c/index.xml" rel="self" type="application/rss+xml"/><link>https://nabozny.io/tag/c/</link><description>Blog o programowaniu i nie tylko</description><lastBuildDate>Mon, 23 Dec 2019 08:24:42 +0000</lastBuildDate><language>pl-PL</language><generator>Hugo 0.167.0</generator><item><title>Co jest nie tak z C++</title><link>https://nabozny.io/co-jest-nie-tak-z-c/</link><dc:creator>maciej</dc:creator><pubDate>Mon, 23 Dec 2019 08:22:02 +0000</pubDate><category>Programowanie</category><category>programowanie</category><category>C++</category><guid isPermaLink="true">https://nabozny.io/co-jest-nie-tak-z-c/</guid><description>Czasami mam wrażenie, że podczas rozwoju C++ coś poszło nie tak i język z wersji na wersję stał się nieczytelnym potworkiem, któremu coraz bliżej do Perla z czytelnością. Pomijając wskaźniki i zarządzanie pamięcią, spójrzmy na taki przykład: lista (wskaźników) funkcji, które mają być wywołane po …</description><content:encoded>&lt;p&gt;Czasami mam wrażenie, że podczas rozwoju C++ coś poszło nie tak i język z wersji na wersję stał się nieczytelnym potworkiem, któremu coraz bliżej do Perla z czytelnością. Pomijając wskaźniki i zarządzanie pamięcią, spójrzmy na taki przykład: lista (wskaźników) funkcji, które mają być wywołane po podaniu określonych parametrów programu, z dodatkową listą pomocniczych parametrów i tekstem pomocy. Docelowo ma pozwolić na takie wywołanie aplikacji w następujący sposób:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;./aplikacja --moje-id 1234 --email ja@domena.pl zamow pizze&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wspomniana lista ma trzymać polecenia typu &amp;ldquo;zamów pizze&amp;rdquo;, wymagane dla nich opcje (z --) oraz funkcje/metodę, która to obsłuży, oczywiście ze swoimi parametrami. Plus help text. W C++:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;std::vector&amp;lt;std::tuple&amp;lt;std::vector&amp;lt;std::string&amp;gt; , void(*)(DApp *, std::vector&amp;lt;std::string&amp;gt;) , std::vector&amp;lt;std::string&amp;gt; , std::string &amp;gt; &amp;gt; command_mappings;&#10;...&#10;tuple&amp;lt;vector&amp;lt;string&amp;gt;, void (*)(DApp *, std::vector&amp;lt;string&amp;gt; ), vector&amp;lt;string&amp;gt;, string &amp;gt; p(vector&amp;lt;string&amp;gt;{&amp;#34;zamow&amp;#34;, &amp;#34;pizze&amp;#34;}, handler, vector&amp;lt;string&amp;gt;{&amp;#34;moje-id&amp;#34;, &amp;#34;email&amp;#34;}, &amp;#34;Zamawia pizze na niby&amp;#34;);&#10;command_mappings.push_back(p);&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Wiem, można to przerobić na klasę/strukturę i będzie miejscami czytelniej. Wiem też, że można użyć gotowych struktur do obsłużenia tego, ale wyszło jak wyszło.&lt;/p&gt;&#10;&lt;p&gt;W Pythonie:&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;command_mappings = []&#10;...&#10;command_mappings.append([&amp;#39;zamow&amp;#39;, &amp;#39;pizze&amp;#39;], handler, [&amp;#34;moje-id&amp;#34;, &amp;#34;email&amp;#34;], &amp;#34;Zamawia pizze na niby&amp;#34;)&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Może to trochę jak porówninie Elektrycznego Malucha z Fordem Escortem. Niby lata produkcji te same i oba mają strefę zgniotu kończącą się na silniku, ale jednak technologia i przeznaczenie inne. W pythonie, jak długo programuje, takie kwiatki nie wychodziły w miarę rozwijania kodu, nawet po latach. Kod zawsze wyglądał dość czytelnie i działał wolno. W C++ na odwrót :) A może po prostu &lt;a href="http://google.com/search?q=pebkac"&gt;PEBKAC&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Wesołych Świąt!&lt;/p&gt;</content:encoded></item><item><title>Jak zrobić to samo nieco szybciej – organizacja danych w pamięci</title><link>https://nabozny.io/jak-zrobic-to-samo-nieco-szybciej-organizacja-danych-w-pamieci/</link><dc:creator>maciej</dc:creator><pubDate>Fri, 24 Nov 2017 14:52:01 +0000</pubDate><category>Programowanie</category><category>programowanie</category><category>C++</category><guid isPermaLink="true">https://nabozny.io/jak-zrobic-to-samo-nieco-szybciej-organizacja-danych-w-pamieci/</guid><description>Krótko na temat tego, czy ten sam algorytm może działać szybciej. Tak! Proste testy, które udało mi się zrobić pokazują wzrost prędkości o ok. 30% przy odpowiednim czarowaniu z danymi, bez ingerencji w sam algorytm.</description><content:encoded>&lt;p&gt;Krótko na temat tego, czy ten sam algorytm może działać szybciej. Tak! Proste testy, które udało mi się zrobić pokazują wzrost prędkości o ok. 30% przy odpowiednim czarowaniu z danymi, bez ingerencji w sam algorytm.&lt;/p&gt;&#10;&lt;p&gt;Skoro nie ruszamy O(n) ani algorytmy, to o czym mowa? O cache procesora i cache instrukcji. Weźmy na przykład ukochanego przez niektórych akademików Quick Sorta. Ze swoim O(n log n) działa szybciej niż Buble Sort z O(n*n). Ale czy na pewno? Na uczelni za to ostatnie pytanie można dostać 2.0 i zostać oddelegowanym na ten sam rok, tylko rok później :)&lt;/p&gt;&#10;&lt;h3 id="l1-l2-l3-ram-i-swap"&gt;L1, L2, L3, ram i swap&lt;/h3&gt;&#10;&lt;p&gt;Większość programistów powinna kojarzyć czym jest cache procesora, ram i swap (lub plik wymiany w znienawidzonych przeze mnie okienkach). Większość też kojarzy jak różni się prędkość zapisu do poszczególnych pamięci, albo chociaż wie, że im bardziej w prawo w tej liście, tym wolniej. Natomiast mało który programista zapytany jak skorzystać z cache procesora będzie wiedział jak to się robi. &amp;ldquo;Gdzieś kiedyś na studiach było, ale dawno i pewnie się pozmieniało, no i pewnie java/python/js zoptymalizuje za mnie&amp;rdquo;.&lt;/p&gt;&#10;&lt;p&gt;A gdyby ktoś Ci powiedział, że układając odpowiednio dane w pamięci możesz przyspieszyć swój kod? No może kosztem jego czytelności.&lt;/p&gt;&#10;&lt;h3 id="l1-i-ram-tak-samo-jak-ram-i-swap"&gt;L1 i RAM tak samo jak RAM i Swap&lt;/h3&gt;&#10;&lt;p&gt;Korzystanie ze swapu jest dla większości oczywiste – gdy coś się nie mieści w RAM&amp;rsquo;ie, to wędruje na dysk. Podobnie jest z cache każdego poziomu. Jeśli procesor nie jest w stanie pomieścić przetwarzanych danych w cache, to wymienia jego zawartość na nowe, aktualnie potrzebne dane z RAM&amp;rsquo;u. I tak jak ze swap&amp;rsquo;em, dzieje się to nie pojedynczych bajtach, ale całych blokach danych.&lt;/p&gt;&#10;&lt;p&gt;Gdybyś miał zrobić program, który nie zmieści się w ramie, to prawdopodobnie zaprojektowałbyś dostęp do pamięci tak, aby jak najmniej skakać po pamięci i powodować wymianę stron z dysku. Podobnie możesz zrobić z przetwarzaniem danych i trzymaniem ich w cache. Efekt nie jest tak zauważalny jak przy swapowaniu, które dosłownie zabija wydajność, ale porównując da się zobaczyć sporą różnicę, nawet 30%.&lt;/p&gt;&#10;&lt;h3 id="zróbmy-przykład"&gt;Zróbmy przykład!&lt;/h3&gt;&#10;&lt;p&gt;Zacznijmy od prostego przykładu – zróbmy z dwóch czarno białych zdjęć jedno, będące średnią jasności. Na przykład:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;image1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;image2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Load images&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;image_diff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;image_diff&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;image1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Na pierwszy rzut oka kodu nie da się zbytnio zoptymalizować. Jeśli tylko dane są ułożone kolumnami (tj. cała pierwsza kolumna, później cała druga itd.), to nie będziemy odczuwać zbyt dużego efektu przeładowywania cache i program zadziała.&lt;/p&gt;&#10;&lt;p&gt;Jeśli natomiast dane w obrazkach są ułożone wierszami, to już tutaj tracimy cały zysk z cache (które jest ładowane przez procesor transparentnie dla programisty). Dane pierwszego i drugiego piksela leżą w obszarach na tyle oddalonych od siebie, że konieczne jest przeładowanie zawartości cache, co spowolni nasz program do prędkości działania RAM&amp;rsquo;u.&lt;/p&gt;&#10;&lt;h3 id="co-jeszcze-zoptymalizować"&gt;Co jeszcze zoptymalizować?&lt;/h3&gt;&#10;&lt;p&gt;Wydaje się, że takie ułożenie to wszystko, na co możemy się porwać, aby było szybciej. Ale nie – jest jeszcze jedna możliwość. Każda iteracja powyższej pętli odwołuje się do trzech różnych obszarów RAM&amp;rsquo;u. Pierwsze dwa to obrazki źródłowe, natomiast trzeci to obrazek z wynikiem.&lt;/p&gt;&#10;&lt;p&gt;Możemy tak ułożyć nasze dane, aby wszystkie trzy obszary przepleść pomiędzy sobą. Dzięki temu kod programu będzie generował żądanie pobrania bloku danych do cache 3 razy częściej, ale tylko w jednym miejscu kodu i tylko jednego (zamiast oryginalnych trzech). W przetwarzaniu potokowym, w które wyposażona jest teraz większość procesorów spowoduje to, że informacja o konieczności pobrania strony pojawia się dość szybko i jest realizowana, gdy pozostała część procesora jeszcze ma co robić.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Load images...&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;W sumie ilość tzw. cache miss w L1, gdy potrzebny obszar pamięci nie jest w cache jest taka sama, ale docelowo zawartość cache L2 (lub niższych) pozwala wczytać te dane trochę szybciej i w praktyce ten sam algorytm wykonuje się ze znaczącą różnicą. W testach na Core2Duo, przy przetwarzaniu 20M bajtów było to około 30%.&lt;/p&gt;&#10;&lt;p&gt;Wracając do naszego akademickiego przykładu Buble Sort vs. Quick Sort – w przypadku dużych dysproporcji w prędkościach przetwarzania danych i ilości tych danych, lepsza złożoność może być &amp;ldquo;zjedzona&amp;rdquo; przez ilość cache-miss generowanych przez Quick Sort, względem Buble Sort idącego prosto przez pamięć, bez skoków. Prawdopodobnie nie będzie to częsty przypadek, ale też należy mieć go na uwadze :)&lt;/p&gt;&#10;&lt;p&gt;Pozostają jeszcze kwestie takie jak instruction cache i przewidywanie skoków w procesorze, ale do tego odsyłam do wujka google.&lt;/p&gt;&#10;&lt;h5 id="zanim-zmierzysz-64ns"&gt;Zanim zmierzysz 64ns&lt;/h5&gt;&#10;&lt;p&gt;Przy testach warto też wziąć pod uwagę optymalizacje kompilatorów. Gcc widząc pętle, z której wyników nikt później nie korzysta (pierwsza, wolniejsza wersja kodu) potrafi ją całkowicie wyciąć z binarnego kodu. Z taką wydajnością wtedy ciężko walczyć :)&lt;/p&gt;</content:encoded></item><item><title>Libsodium – kryptografia w łatwiejszym wydaniu</title><link>https://nabozny.io/libsodium-kryptografia-w-latwiejszym-wydaniu/</link><dc:creator>maciej</dc:creator><pubDate>Fri, 21 Jul 2017 21:45:40 +0000</pubDate><category>Programowanie</category><category>kryptografia</category><category>programowanie</category><category>C++</category><guid isPermaLink="true">https://nabozny.io/libsodium-kryptografia-w-latwiejszym-wydaniu/</guid><description>Już kilka razy potrzebowałem użyć kryptografii do jakiegoś zadania. Zwykle przychodził z “pomocą” potworek o nazwie openssl, za pomocą którego można było wyczarować cuda. Problemem była jedynie składnia, którą trudno zapamiętać, bo “potworek” jest szyty na miarę profesjonalnych zastosowań.</description><content:encoded>&lt;p&gt;Już kilka razy potrzebowałem użyć kryptografii do jakiegoś zadania. Zwykle przychodził z &amp;ldquo;pomocą&amp;rdquo; potworek o nazwie &lt;em&gt;openssl&lt;/em&gt;, za pomocą którego można było wyczarować cuda. Problemem była jedynie składnia, którą trudno zapamiętać, bo &amp;ldquo;potworek&amp;rdquo; jest szyty na miarę profesjonalnych zastosowań.&lt;/p&gt;&#10;&lt;p&gt;API &amp;ldquo;potworka&amp;rdquo; jest jeszcze bardziej pokręcone i wymaga ogromnej wiedzy, już na sam początek, co dla niewprawionych w bojach z kryptografią może być i tak bardzo dużym wyzwaniem.&lt;/p&gt;&#10;&lt;p&gt;Niedawno, szukając jakiejś alternatywy dla wołania zewnętrznego polecenia openssl albo gpg, dla projektu &lt;a href="https://github.com/cloudover/libdinemic/"&gt;libdinemic&lt;/a&gt; udało mi się znaleźć bibliotekę Sodium, która jest następcą innego, ponoć podobnego narzędzia NaCl. Biblioteka ta pozwala w bardzo przyjemny sposób ogarnąć podstawowe zadania związane z kryptografią:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Podpisy cyfrowe – generujące kawałek danych potwierdzający, że właściciel prywatnego klucza coś napisał&lt;/li&gt;&#10;&lt;li&gt;Szyfrowanie symetryczne – pozwalające zamienić ciąg ważnych dla nas danych w (prawie) bezużyteczne śmieci, możliwe do odszyfrowania jedynie po podaniu hasła&lt;/li&gt;&#10;&lt;li&gt;Szyfrowanie asymetryczne – pozwalające zaszyfrowanie komuś danych posiadając jedynie jego publiczny, znany wszystkim klucz. Dzięki temu tylko ta osoba ta może odszyfrować, korzystając z prywatnej części klucza&lt;/li&gt;&#10;&lt;li&gt;Funkcje skrótu SHA2&lt;/li&gt;&#10;&lt;li&gt;&amp;hellip; i kilka innych fajnych narzędzi związanych z bezpieczeństwem&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="jak-się-za-to-zabrać"&gt;Jak się za to zabrać?&lt;/h3&gt;&#10;&lt;p&gt;Będziesz potrzebował samą bibliotekę, jej pliki nagłówkowe, kompilator i edytor tekstu:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get install libsodium-dev gcc gedit&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Aby skompilować coś, co zachwile stworzysz, dodaj opcję &lt;em&gt;-lsodium&lt;/em&gt; do kompilatora:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gcc -o program -lsodium program.c&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip;lub skorzystaj z gotowego narzędzia typu &lt;em&gt;make&lt;/em&gt;, &lt;em&gt;qmake&lt;/em&gt; albo &lt;em&gt;cmake&lt;/em&gt;.&lt;/p&gt;&#10;&lt;h3 id="klucz-prywatny-i-publiczny--po-co-to"&gt;Klucz prywatny i publiczny – po co to&lt;/h3&gt;&#10;&lt;p&gt;Zanim przejdziemy do kolejnych kroków – kilka zdań o kryptografii asymetrycznej. Jak źle by to nie było omówione na studiach, warto wiedzieć co ona daje i wierzyć, że jeszcze nikt z NSA nie złamał jej zabezpieczeń (albo i nie wierzyć). W dużym uproszczeniu, kryptografia asymetryczna bazuje na parach kluczy (liczb), z których jedna, prywatna, to zwykle duża losowa liczba. W niektórych algorytmach musi to być liczba pierwsza. Druga liczba, publiczna jest obliczana na podstawie tej pierwszej, prywatnej.&lt;/p&gt;&#10;&lt;p&gt;Generowanie drugiej liczny jest wykonywane w taki sposób, aby operacja odwrotna była bardzo żmudna i długotrwała. Dobrym porównaniem jest mieszanie farbek. Jeśli znasz proporcje (Twój klucz prywatny), to możesz szybko wymieszać podstawowe kolory i otrzymać identyfikujący Cię kolor. Każda wiadomość pomaziana Twoim kolorem będzie automatycznie oznaczona jako nadana przez Ciebie, bo tylko Ty potrafisz zrobić taki kolor. Jeśli natomiast ktoś chciałby podrobić Twój kolor, to musiałby próbować różnych zestawień barw, co trwało by znacznie dłużej. Podobnie miało to miejsce z tajną recepturą KFC. Wszyscy próbowali ją podrabiać, ale do czasu jej wycieku oryginalny smak, bazujący na proporcjach kilkunastu przypraw pozostawał tylko w KFC.&lt;/p&gt;&#10;&lt;p&gt;O ile kolory czy proporcje przypraw można by próbować dość łatwo odtworzyć, bo nie ma aż tylu możliwości, to obliczenie prywatnego klucza kryptograficznego (proporcji przypraw) na podstawie klucza publicznego (smaku) może trwać zwykle latami na pojedynczym komputerze. Dla tego jest to uznawane za bezpieczny środek komunikacji, a dodatkowo daje możliwość udostępnienia wszystkim czegoś (smaku, koloru, publicznego klucza), który może zweryfikować czy to my lub umożliwić zaszyfrowanie nam wiadomości, którą odczytamy tylko my.&lt;/p&gt;&#10;&lt;h3 id="podpisy-cyfrowe"&gt;Podpisy cyfrowe&lt;/h3&gt;&#10;&lt;p&gt;Pierwszym zadaniem z &lt;em&gt;libsodium&lt;/em&gt; było dla mnie zakodowanie modułu umożliwiającego generowanie podpisów cyfrowych w &lt;em&gt;libdinemic&lt;/em&gt;. Miało to uwierzytelnić każdą zmianę wykonywaną w rozproszonej bazie dla wielu hostów, bez korzystania z blokad i tym podobnych mechanizmów. W zamian miały być wykorzystane właśnie podpisy cyfrowe – tylko osoba posiadająca klucz prywatny przypisany do obiektu w bazie może go zaktualizować.&lt;/p&gt;&#10;&lt;p&gt;Jak wygenerować taki podpis za pomocą &lt;em&gt;libsodium&lt;/em&gt;? Potrzebujemy wiadomość (update stanu bazy) oraz parę kluczy, prywatny i publiczny. Klucze można wygenerować jedną funkcją:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sodium.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;sign_secret_key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;crypto_sign_SECRETKEYBYTES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;sign_public_key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;crypto_sign_PUBLICKEYBYTES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;crypto_sign_keypair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sign_public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sign_secret_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;crypto_sign_keypair&lt;/em&gt; zapisze do podanych zmiennych klucz prywatny (losowy ciąg danych) i odpowiadający mu klucz publiczny. Libsodium używa do tego algorytmów opartych o krzywe eliptyczne, przez co klucze są znacznie krótsze od tych znanych z RSA. Mając dwa klucze możemy wygenerować wiadomość i podpisać ją cyfrowo naszym prywatnym kluczem:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;crypto_sign_BYTES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Ala ma kota a kot ma Ale&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;crypto_sign_detached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sign_secret_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Podpis cyfrowy będzie zapisany do zmiennej sig, która ma stałą, określoną przez crypto_sign_BYTES długość.&lt;/p&gt;&#10;&lt;p&gt;W ten sposób możemy rozpowszechnić nasz publiczny klucz, za pomocą którego inne osoby lub programy będą mogły potwierdzić autentyczność naszej wiadomości. Aby zweryfikować podpisany ciąg znaków wystarczy sprawdzić:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;crypto_sign_BYTES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;//pobieramy podpis&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;//pobieramy wiadomość&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;crypto_sign_verify_detached&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sign_public_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// To jest fałszywy podpis!&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Podpis się zgadza&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="szyfrowanie-danych"&gt;Szyfrowanie danych&lt;/h3&gt;&#10;&lt;p&gt;Szyfrowanie danych z libsodium wygląda podobnie, aczkolwiek wymaga użycia innego zestawu funkcji i algorytmów. Po pierwsze musimy wygenerować inny zestaw kluczy za pomocą innej funkcji – &lt;em&gt;crpto_box_keypair&lt;/em&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;encryption_secret_key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;crypto_box_SECRETKEYBYTES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;encryption_public_key&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;crypto_box_PUBLICKEYBYTES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;crypto_box_keypair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encryption_public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encryption_secret_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Następnie możemy rozpowszechnić publiczny klucz. Szyfrowanie działa trochę inaczej – tutaj do wygenerowania danych nadawcy potrzebny jest publiczny klucz. Dzięki temu tylko odbiorca może odszyfrować swoją wiadomość. Odwrotnie było w przypadku podpisów – tylko nadawca mógł się podpisać pod wiadomością, a zweryfikować mógł ktokolwiek, używając jego klucza publicznego.&lt;/p&gt;&#10;&lt;p&gt;Do zaszyfrowania wiadomości będziemy potrzebowali dodatkowego obszaru pamięci, do którego libsodium zapisze zaszyfrowane dane:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Ala ma kota a kot nie ma Ali&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;encrypted_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;crypto_box_SEALBYTES&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nf"&gt;crypto_box_seal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;encryption_public_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Wysylamy wiadomosc w swiat&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Odbiorca wiadomości może ją odszyfrować posiadając swój prywatny klucz:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Odebranie wiadomosci&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;decrypted_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;encrypted_message_length&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;crypto_box_seal_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decrypted_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;encrypted_message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;encrypted_message_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;encryption_public_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;encryption_secret_key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// nie udalo sie odszyfrowac wiadomosci&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Mamy wiadomosc!&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Do powyższych przykładów należy podejść czysto edukacyjnie i zwrócić uwagę zwłaszcza na funkcje &lt;em&gt;strlen&lt;/em&gt;, które w przypadku danych binarnych mogą zwrócić niepoprawne wartości.&lt;/p&gt;</content:encoded></item></channel></rss>