{"id":409975,"date":"2024-06-29T21:05:52","date_gmt":"2024-06-29T21:05:52","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=409975"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=409975","title":{"rendered":"<span>\u0421++17 wrapper \u0434\u043b\u044f OpenSSL: ECDH \u0438 AES 256<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/054\/9ec\/005\/0549ec005a97a11db3c8e8fec9d2c762.jpg\" width=\"753\" height=\"428\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/054\/9ec\/005\/0549ec005a97a11db3c8e8fec9d2c762.jpg\" data-blurred=\"true\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0421++ \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438. \u042f \u0441\u0440\u0430\u0437\u0443 \u043e\u0431\u0440\u0430\u0442\u0438\u043b \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0435\u0441\u044f \u0432 TLS 1.3. \u041e\u043f\u0443\u0441\u0442\u0438\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e TLS-\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u0438 \u0432\u0437\u044f\u0432 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0437\u0430 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u044f \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043b \u043a \u0440\u0430\u0431\u043e\u0442\u0435. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0432\u044b\u0438\u0441\u043a\u0438\u0432\u0430\u0442\u044c \u0432 \u0432\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445(\u043e\u0442 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 OpenSSL, \u0434\u043e \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043d\u0430 stackoverflow), \u0430 \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0434\u0430\u0436\u0435 \u0434\u043e\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0441\u043a\u0440\u0435\u043f\u0438\u0442\u044c \u043a\u0443\u0441\u043a\u0438 \u043a\u043e\u0434\u0430 \u0438\u0437 \u044d\u0442\u0438\u0445 \u0441\u0430\u043c\u044b\u0445 \u0440\u0430\u0437\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0443\u043c\u0430\u043d\u043d\u043e\u0433\u043e, \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e, \u0441 \u0446\u0435\u043b\u044c\u044e \u043f\u043e\u043c\u043e\u0447\u044c \u0442\u0435\u043c \u043a\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0432\u044f\u0437\u043a\u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9F%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB_%D0%94%D0%B8%D1%84%D1%84%D0%B8_%E2%80%94_%D0%A5%D0%B5%D0%BB%D0%BB%D0%BC%D0%B0%D0%BD%D0%B0_%D0%BD%D0%B0_%D1%8D%D0%BB%D0%BB%D0%B8%D0%BF%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D0%BA%D1%80%D0%B8%D0%B2%D1%8B%D1%85\" rel=\"noopener noreferrer nofollow\">\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 \u0414\u0438\u0444\u0444\u0438-\u0425\u0435\u043b\u043b\u043c\u0430\u043d \u043d\u0430 \u044d\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043a\u0440\u0438\u0432\u044b\u0445<\/a> \u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/AES_(%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82_%D1%88%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)\" rel=\"noopener noreferrer nofollow\">\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u043e\u0433\u043e \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f AES 256<\/a> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 OpenSSL \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 ECDH<\/h2>\n<p>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"cpp\">#ifndef SECURITY_HPP #define SECURITY_HPP  #include &lt;openssl\/ecdh.h> #include \"byte_array.hpp\"  namespace security {  \/**  * @brief AES256 key and initialization vector  *\/ struct AES_t {   uint8_t key[32] = {     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0,0,0,0,0,     0,0   };   uint8_t init_vector[16] = {     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0   };   bool isEmpty() const {       static const AES_t empty_aes;       return !std::memcmp(this, &amp;empty_aes, sizeof (AES_t));   }   void clear() {*this = AES_t();}   AES_t() = default;   AES_t(ByteArray data) {     *this = *reinterpret_cast&lt;AES_t*>(data.begin());   } };  \/\/ ECDH \/**  * @brief Generate ECDH key pair  * @return ECDH key pair  *\/ EVP_PKEY* genKey();  \/**  * @brief Free key memory  * @param key  *\/ void freeKey(EVP_PKEY* key);  \/**  * @brief Extract public key from key pair  * @param key_pair  * @return ByteArray with public key  *\/ ByteArray extractPublicKey(EVP_PKEY* key_pair);  \/**  * @brief Extract private key from key pair  * @param key_pair  * @return ByteArray with private key  *\/ ByteArray extractPrivateKey(EVP_PKEY* key_pair);  \/**  * @brief Conver ByteArrays to key pair  * @param priv_key_raw  * @param pub_key_raw  * @return ECDH key pair  *\/ EVP_PKEY* getKeyPair(ByteArray priv_key_raw, ByteArray pub_key_raw);  \/**  * @brief Get AES256 key and initialization vector from ECDH keys  * @param peer_key - public key from other side  * @param key_pair - private key from this side  * @return AES256 key and initialization vector  *\/ AES_t getSecret(ByteArray peer_key, EVP_PKEY* key_pair);  \/\/ AES256 \/**  * @brief Encrypt message  * @param plain_text  * @param aes_struct  * @return Cyphertext  *\/ ByteArray encrypt(ByteArray plain_text, AES_t aes_struct);  \/**  * @brief Decrypt message  * @param ciphertext  * @param aes_struct  * @return plain_text  *\/ ByteArray decrypt(ByteArray ciphertext, AES_t aes_struct);  \/** * @brief Encode data with base64 * @param decoded * @return *\/ ByteArray encodeBase64(ByteArray decoded);  \/** * @brief Decode base64 data * @param encoded * @return *\/ ByteArray decodeBase64(ByteArray encoded);  }  #endif \/\/ SECURITY_HPP <\/code><\/pre>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043d\u0438\u0436\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 OpenSSL \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0443\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<pre><code class=\"cpp\">\/\/ \u0444\u0430\u0439\u043b security.cpp #include \"security.hpp\"  #include &lt;openssl\/conf.h> #include &lt;openssl\/err.h> \/\/ EVP #include &lt;openssl\/evp.h> \/\/ AES #include &lt;openssl\/aes.h> \/\/ ECDH #include &lt;openssl\/ec.h> #include &lt;openssl\/pem.h>  #include &lt;stdexcept>  \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a void handleErrors() {   ERR_print_errors_fp(stderr);   throw std::runtime_error(\"Security error\"); }  \/\/ \u041d\u0438\u0436\u0435\u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0437\u0434\u0435\u0441\u044c<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u0433\u0435\u043d\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u044b \u043a\u043b\u044e\u0447\u0435\u0439 ECDH. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 ECDH \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 OpenSSL &#8212; <a href=\"https:\/\/wiki.openssl.org\/index.php\/EVP\" rel=\"noopener noreferrer nofollow\">EVP<\/a>.<\/p>\n<pre><code class=\"cpp\">EVP_PKEY* security::genKey() {   EVP_PKEY* key_pair = nullptr;\/\/ \u041a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u043f\u0430\u0440\u0430   EVP_PKEY_CTX* param_gen_ctx = nullptr; \/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432   EVP_PKEY_CTX* key_gen_ctx = nullptr;\/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043b\u044e\u0447\u0430   EVP_PKEY* params= nullptr;\/\/ \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043b\u044e\u0447\u0430    \/\/ \u0412\u044b\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 EC-\u043a\u043b\u044e\u0447\u0430   if(!(param_gen_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) handleErrors();   \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 EC-\u043a\u043b\u044e\u0447\u0430   if(!EVP_PKEY_paramgen_init(param_gen_ctx)) handleErrors();    \/\/ \u0417\u0430\u0434\u0430\u0451\u043c \u044d\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u043a\u0443\u044e \u043a\u0440\u0438\u0432\u0443\u044e prime256v1   if(!EVP_PKEY_CTX_set_ec_paramgen_curve_nid(param_gen_ctx, NID_X9_62_prime256v1))     handleErrors();    \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b   if(!EVP_PKEY_paramgen(param_gen_ctx, &amp;params)) handleErrors();    \/\/ \u0412\u044b\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 EC-\u043a\u043b\u044e\u0447\u0430   if(!(key_gen_ctx = EVP_PKEY_CTX_new(params, nullptr))) handleErrors();   \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 EC-\u043a\u043b\u044e\u0447\u0430   if(!EVP_PKEY_keygen_init(key_gen_ctx)) handleErrors();   \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043a\u043b\u044e\u0447   if(!EVP_PKEY_keygen(key_gen_ctx, &amp;key_pair)) handleErrors();    \/\/ \u0412\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432   EVP_PKEY_CTX_free(param_gen_ctx);   \/\/ \u0412\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043b\u044e\u0447\u0430   EVP_PKEY_CTX_free(key_gen_ctx);   \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043f\u0430\u0440\u044b   return key_pair; }<\/code><\/pre>\n<h2>\u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 ECDH \u0438\u0437 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043f\u0430\u0440\u044b EVP_PKEY* \u0432 &#171;\u0441\u044b\u0440\u043e\u0439 \u0431\u0443\u0444\u0444\u0435\u0440&#187;<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043f\u043e \u0441\u0435\u0442\u0438 \u0438\u043b\u0438 \u0436\u0435 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u043a\u0430\u043a \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0438 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438\u0437 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044f \u043d\u0430 EVP_PKEY.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043c\u044b \u0441 C++ \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u044b\u0440\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>std::vector&lt;uint8_t><\/code> \u0438\u043b\u0438 \u043a\u043b\u0430\u0441\u0441 \u043d\u0430 \u043f\u043e\u0434\u043e\u0431\u0438\u0438 \u043d\u0438\u0436\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e:<\/p>\n<pre><code class=\"cpp\">\/\/ \u0424\u0430\u0439\u043b byte_array.hpp #ifndef BYTE_ARRAY_HPP #define BYTE_ARRAY_HPP  #include &lt;cstdint> #include &lt;cstring> #include &lt;utility> #include &lt;new> #include &lt;malloc.h>  class ByteArray {   uint8_t* byte_array = nullptr;   uint64_t _length = 0;   public:   typedef uint8_t* iterator;   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e   ByteArray() = default;      \/\/ \u041a\u043e\u0441\u043d\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0441 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u0438   ByteArray(uint64_t length)     : byte_array(new uint8_t[length]),   _length(length) {}      \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0437 \u0441\u044b\u0440\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430   ByteArray(void* buffer, uint64_t length)     : byte_array(new uint8_t[length]),       _length(length) {         memcpy(byte_array, buffer, _length);       }      \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f   ByteArray(ByteArray&amp; other)     : byte_array(new uint8_t[other._length]),       _length(other._length) {         memcpy(byte_array, other.byte_array, _length);       }      \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f   ByteArray(ByteArray&amp;&amp; other)     : byte_array(other.byte_array),       _length(other._length) {         other.byte_array = nullptr;       }      \/\/ \u0414\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440   ~ByteArray() {if(byte_array) delete[] byte_array;}      \/\/ \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440   void resize(uint64_t new_length) {   _length = new_length;   byte_array = (uint8_t*)realloc(byte_array, _length);   }      \/\/ \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440   iterator addSize(uint64_t add) {     byte_array = (uint8_t*)realloc(byte_array, _length + add);     iterator it = byte_array + _length;     _length += add;     memset(it, 0, add);     return it;   }      \/\/ Getter \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430   inline uint64_t length() {return _length;}   \/\/ \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0432\u0437\u044f\u0442\u0438\u0435 \u0435\u043b\u0435\u043c\u0435\u043d\u0442\u0430   inline uint8_t&amp; operator[](uint64_t index) {return byte_array[index];}   \/\/ \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u0438\u044f   inline ByteArray&amp; operator=(ByteArray other) {     this->~ByteArray();     return *new(this) ByteArray(std::move(other));   }      \/\/ \u0418\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f range-based for   \/\/ for(auto byte : byte_array_object) {...}   inline iterator begin() {return byte_array;}   inline iterator end() {return byte_array + _length;} };  #endif \/\/ BYTE_ARRAY_HPP<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430:<\/p>\n<pre><code class=\"cpp\">ByteArray security::extractPublicKey(EVP_PKEY* key_pair) {   EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(key_pair);   EC_POINT* ec_point = const_cast&lt;EC_POINT*>(EC_KEY_get0_public_key(ec_key));    EVP_PKEY* public_key = EVP_PKEY_new();   EC_KEY* public_ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);    EC_KEY_set_public_key(public_ec_key, ec_point);   EVP_PKEY_set1_EC_KEY(public_key, public_ec_key);     EC_KEY *temp_ec_key = EVP_PKEY_get0_EC_KEY(public_key);    if(temp_ec_key == NULL) handleErrors();    const EC_GROUP* group = EC_KEY_get0_group(temp_ec_key);   point_conversion_form_t form = EC_GROUP_get_point_conversion_form(group);    unsigned char* pub_key_buffer;   size_t length = EC_KEY_key2buf(temp_ec_key, form, &amp;pub_key_buffer, NULL);   if(!length) handleErrors();   ByteArray data(pub_key_buffer, length);    OPENSSL_free(pub_key_buffer);   EVP_PKEY_free(public_key);   EC_KEY_free(ec_key);   EC_KEY_free(public_ec_key);   EC_POINT_free(ec_point);    return data; }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430:<\/p>\n<pre><code class=\"cpp\">ByteArray security::extractPrivateKey(EVP_PKEY* key_pair) {   EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(key_pair);   const BIGNUM* ec_priv = EC_KEY_get0_private_key(ec_key);   int length = BN_bn2mpi(ec_priv, nullptr);   ByteArray data(length);   BN_bn2mpi(ec_priv, data.begin());   return data; }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u044b \u043a\u043b\u044e\u0447\u0435\u0439 EVP \u0438\u0437 \u0434\u0432\u0443\u0445 &#171;\u0441\u044b\u0440\u044b\u0445 \u0431\u0443\u0444\u0435\u0440\u043e\u0432&#187; \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439:<\/p>\n<pre><code class=\"cpp\">EVP_PKEY* security::getKeyPair(ByteArray priv_key_raw, ByteArray pub_key_raw) {   EVP_PKEY* key_pair = EVP_PKEY_new();   EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);    const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);   EC_POINT* ec_point = EC_POINT_new(ec_group);   EC_POINT_oct2point(ec_group, ec_point, pub_key_raw.begin(), pub_key_raw.length(), nullptr);   EC_KEY_set_public_key(ec_key, ec_point);   EC_POINT_free(ec_point);    BIGNUM* priv = BN_mpi2bn(priv_key_raw.begin(), priv_key_raw.length(), nullptr);   EC_KEY_set_private_key(ec_key, priv);   BN_free(priv);    EVP_PKEY_set1_EC_KEY(key_pair, ec_key);   EC_KEY_free(ec_key);   return key_pair; }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u043d\u0435 \u0432 \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u043c, \u0430 \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0444\u0444\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438 base64 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 OpenSSL:<\/p>\n<pre><code class=\"cpp\">\/\/ \u0417\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 base64 ByteArray security::encodeBase64(ByteArray decoded) {   ByteArray encoded((4*((decoded.length()+2)\/3)) + 1);   EVP_EncodeBlock(encoded.begin(), decoded.begin(), decoded.length());   return encoded; }  \/\/ \u0414\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437 base64 ByteArray security::decodeBase64(ByteArray encoded) {   ByteArray decoded((3*encoded.length()\/4) + 1);   size_t recived_data_size = EVP_DecodeBlock(decoded.begin(), encoded.begin(), encoded.length());   if(recived_data_size &lt; decoded.length())     decoded.resize(recived_data_size);   return decoded; }<\/code><\/pre>\n<h2>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u0431\u0449\u0435\u0433\u043e \u0441\u0435\u043a\u0440\u0435\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b ECDH<\/h2>\n<p>\u041a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u043f\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043f\u0430\u0440\u0435 \u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u043c\u0435\u043d\u044f\u043b\u0430\u0441\u044c \u0441\u0432\u043e\u0438\u043c\u0438 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043a\u043b\u044e\u0447\u0430\u043c\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u043a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c &#171;\u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442&#187; \u0445\u044d\u0448 \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043a\u043b\u044e\u0447 AES 256. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043a\u043b\u044e\u0447\u0430 AES 256:<\/p>\n<pre><code class=\"cpp\">struct AES_t {   \/\/ 32 \u0431\u0430\u0439\u0442\u0430 \u0434\u043b\u044f \u043a\u043b\u044e\u0447\u0430   uint8_t key[32] = {     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0,0,0,0,0,     0,0   };   \/\/ 16 \u0431\u0430\u0439\u0442 \u0434\u043b\u044f \u0432\u0435\u043a\u0442\u043e\u0440\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438   uint8_t init_vector[16] = {     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0   };      \/\/ \u0412 \u043e\u0431\u0449\u0435\u0439 \u0441\u0443\u043c\u043c\u0435 \u0440\u0430\u0437\u043c\u0435\u0440 \u043a\u043b\u044e\u0447\u0430 48 \u0431\u0430\u0439\u0442 \u0438\u043b\u0438 384 \u0431\u0438\u0442\u0430      \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u0443\u0441\u0442\u043e\u0442\u0443 \u043a\u043b\u044e\u0447\u0430   bool isEmpty() const {     static const AES_t empty_aes;     return !std::memcmp(this, &amp;empty_aes, sizeof (AES_t));   }   \/\/ \u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u043a\u043b\u044e\u0447   void clear() {*this = AES_t();}   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e   AES_t() = default;   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0438\u0437 ByteArray   AES_t(ByteArray data) {     *this = *reinterpret_cast&lt;AES_t*>(data.begin());   } }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f AES 256 \u043a\u043b\u044e\u0447\u0430 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 48 \u0431\u0430\u0439\u0442 \u0438\u043b\u0438 384 \u0431\u0438\u0442\u0430, \u0430 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f AES 256 \u043a\u043b\u044e\u0447\u0430 \u0438\u0437 \u043e\u0431\u0449\u0435\u0433\u043e \u0441\u0435\u043a\u0440\u0435\u0442\u0430 \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442 \u0445\u044d\u0448-\u0434\u0430\u0439\u0434\u0436\u0435\u0441\u0442 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0432 384 \u0431\u0438\u0442, \u0442\u043e \u0435\u0441\u0442\u044c \u043d\u0430\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u0442\u0430\u043a\u0438\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0445\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u043a sha384(sha2) \u0438 sha3_384(\u0440\u0430\u043d\u0435\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u043a\u0430\u043a Keccak). \u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c sha3 \u043a\u0430\u043a \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 sha2, \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u0438\u043d\u044f\u0442\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0447\u0442\u043e \u043e\u0431\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0447\u0442\u043e \u043d\u0435 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e sha1. \u041e\u0431\u0430 \u044d\u0442\u0438\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f OpenSSL, \u043d\u043e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0441\u0451-\u0442\u0430\u043a\u0438 \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u043c sha3_384.<\/p>\n<pre><code class=\"cpp\">AES_t security::getSecret(ByteArray peer_key, EVP_PKEY* key_pair) {   EC_KEY *temp_ec_key = nullptr;   EVP_PKEY *peerkey = nullptr;    \/\/ \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447   \/\/ \u0438\u0437 \u0441\u044b\u0440\u043e\u0433\u043e \u0431\u0443\u0444\u0444\u0435\u0440\u0430 \u0432 EVP_PKEY*   temp_ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);   if(temp_ec_key == nullptr)     handleErrors();   if(EC_KEY_oct2key(temp_ec_key, peer_key.begin(), peer_key.length(), NULL) != 1)     handleErrors();   if(EC_KEY_check_key(temp_ec_key) != 1) handleErrors();   peerkey = EVP_PKEY_new();   if(peerkey == NULL)     handleErrors();   if(EVP_PKEY_assign_EC_KEY(peerkey, temp_ec_key)!= 1)     handleErrors();    \/\/ \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u0431\u0449\u0435\u0433\u043e \u0441\u0435\u043a\u0440\u0435\u0442\u0430   EVP_PKEY_CTX *derivation_ctx = EVP_PKEY_CTX_new(key_pair, NULL);   EVP_PKEY_derive_init(derivation_ctx);   EVP_PKEY_derive_set_peer(derivation_ctx, peerkey);   size_t lenght;\/\/ \u0420\u0430\u0437\u043c\u0435\u0440 \u043e\u0431\u0449\u0435\u0433\u043e \u0441\u0435\u043a\u0440\u0435\u0442\u0430   void* ptr;\/\/ \u0423\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0431\u0443\u0444\u0444\u0435\u0440 \u0441 \u043e\u0431\u0449\u0438\u043c \u0441\u0435\u043a\u0440\u0435\u0442\u043e\u043c   if(1 != EVP_PKEY_derive(derivation_ctx, NULL, &amp;lenght)) handleErrors();   if(NULL == (ptr = OPENSSL_malloc(lenght))) handleErrors();   if(1 != (EVP_PKEY_derive(derivation_ctx, (unsigned char*)ptr, &amp;lenght))) handleErrors();   EVP_PKEY_CTX_free(derivation_ctx);   EVP_PKEY_free(peerkey);    \/\/ \u0425\u044d\u0448\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442 \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 AES_t   AES_t aes_key;   EVP_MD_CTX *mdctx;   if((mdctx = EVP_MD_CTX_new()) == NULL)     handleErrors();   if(1 != EVP_DigestInit_ex(mdctx, EVP_sha384(), NULL))     handleErrors();   if(1 != EVP_DigestUpdate(mdctx, ptr, lenght))     handleErrors();   unsigned int length;   if(1 != EVP_DigestFinal_ex(mdctx, (unsigned char*)&amp;aes_key, &amp;length))     handleErrors();   EVP_MD_CTX_free(mdctx);   OPENSSL_free(ptr);   return aes_key; }<\/code><\/pre>\n<h2>\u0428\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0434\u0435\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c AES 256<\/h2>\n<p>\u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u0431\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0438\u043c\u0435\u044e\u0442 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 AES 256 \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"cpp\">ByteArray security::encrypt(ByteArray plain_text, AES_t aes_struct) {   \/\/ \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u0434\u043b\u0438\u043d\u043d\u0443 \u0448\u0438\u0444\u0440\u043e\u0442\u0435\u043a\u0441\u0442\u0430   ByteArray ciphertext(plain_text.length() % AES_BLOCK_SIZE == 0                        ? plain_text.length()                        : (plain_text.length() \/ AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE);    \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0448\u0438\u0444\u0440\u0430   EVP_CIPHER_CTX *ctx;   if(!(ctx = EVP_CIPHER_CTX_new()))     handleErrors();   if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, aes_struct.key, aes_struct.init_vector))     handleErrors();    \/\/ \u0428\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430   int f_length, s_length;   if(1 != EVP_EncryptUpdate(ctx, ciphertext.begin(), &amp;f_length, plain_text.begin(), plain_text.length()))     handleErrors();    \/\/ \u0418\u043d\u043e\u0433\u0434\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0448\u0438\u0444\u0440\u043e\u0442\u0435\u043a\u0441\u0442\u0430 \u0442\u0440\u0435\u0431\u0443\u0442\u0435\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 AES \u0431\u043b\u043e\u043a   if(uint64_t(f_length) == ciphertext.length())     ciphertext.addSize(AES_BLOCK_SIZE);   else if(uint64_t(f_length) > ciphertext.length())     throw std::runtime_error(\"Predicted ciphertext size lower then actual!\");    \/\/ \u0417\u0430\u043f\u0438\u0441\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e AES \u0431\u043b\u043e\u043a\u0430   if(1 != EVP_EncryptFinal_ex(ctx, ciphertext.begin() + f_length, &amp;s_length))     handleErrors();      \/\/ \u0423\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u0448\u0438\u0444\u0440\u043e\u0442\u0435\u043a\u0441\u0442\u0430   if(uint64_t reuired_length = f_length + s_length; reuired_length &lt; ciphertext.length())     ciphertext.resize(f_length + s_length);   else if(reuired_length > ciphertext.length())     throw std::runtime_error(\"Predicted ciphertext size lower then actual!\");    \/\/ \u0412\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0448\u0438\u0444\u0440\u0430   EVP_CIPHER_CTX_free(ctx);    return ciphertext; }<\/code><\/pre>\n<p>\u0414\u0435\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"cpp\">ByteArray security::decrypt(ByteArray ciphertext, AES_t aes_struct) {   ByteArray plain_text(ciphertext.length());    \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0448\u0438\u0444\u0440\u0430   EVP_CIPHER_CTX *ctx;   if(!(ctx = EVP_CIPHER_CTX_new()))     handleErrors();   if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, aes_struct.key, aes_struct.init_vector))     handleErrors();    \/\/ \u0414\u0435\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0430 \u0448\u0438\u0444\u0440\u043e\u0442\u0435\u043a\u0441\u0442\u0430   int f_length, s_length;   if(1 != EVP_DecryptUpdate(ctx, plain_text.begin(), &amp;f_length, ciphertext.begin(), ciphertext.length()))     handleErrors();   if(1 != EVP_DecryptFinal_ex(ctx, plain_text.begin() + f_length, &amp;s_length))     handleErrors();      \/\/ \u0423\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0431\u0443\u0444\u0444\u0435\u0440\u0430 \u0434\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445   plain_text.resize(f_length + s_length);    \/\/ \u0412\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u0438 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0448\u0438\u0444\u0440\u0430   EVP_CIPHER_CTX_free(ctx);    return plain_text; }<\/code><\/pre>\n<h2>\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/h2>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0448\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430:<\/p>\n<pre><code class=\"cpp\">#include \"security.hpp\" #include &lt;iostream>  int main(int argc, char* argv[]) {   using namespace security;   \/\/ \u0410\u043b\u0438\u0441\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043a\u043b\u044e\u0447   EVP_PKEY* alice_key_pair = genKey();   \/\/ \u0410\u043b\u0438\u0441\u0430 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447   ByteArray alice_peer_key = extractPublicKey(alice_key_pair);      \/\/ \u0411\u043e\u0431 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043a\u043b\u044e\u0447   EVP_PKEY* bob_key_pair = genKey();   \/\/ \u0411\u043e\u0431 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447   ByteArray bob_peer_key = extractPublicKey(bob_key_pair);      \/\/ \u0410\u043b\u0438\u0441\u0430 \u0438 \u0411\u043e\u0431 \u043e\u0431\u043c\u0435\u043d\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043a\u043b\u044e\u0447\u0430\u043c\u0438   \/\/ \u0447\u0435\u0440\u0435\u0437 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u043a\u0430\u043d\u0430\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445      \/\/ \u0411\u043e\u0431 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u043d\u044b\u0439 AES 256 \u043a\u043b\u044e\u0447   AES_t bob_aes_key = getSecret(alice_peer_key, bob_key_pair);      \/\/ \u0410\u043b\u0438\u0441\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u043d\u044b\u0439 AES 256 \u043a\u043b\u044e\u0447   AES_t alice_aes_key = getSecret(bob_peer_key, alice_key_pair);      \/\/ \u0410\u043b\u0438\u0441\u0430 \u0448\u0438\u0444\u0440\u0443\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435   std::string alice_msg = \"Hello, Bob\";   ByteArray alice_msg_buffer(alice_msg.data(), alice_msg.length() + 1);   ByteArray alice_enc_msg = encrypt(alice_msg_buffer, alice_aes_key);   \/\/ \u0418 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c\u0443 \u043a\u0430\u043d\u0430\u043b\u0443 \u0411\u043e\u0431\u0443      \/\/ \u0411\u043e\u0431 \u0448\u0438\u0444\u0440\u0443\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435   std::string bob_msg = \"Hello, Alice\";   ByteArray bob_msg_buffer(bob_msg.data(), bob_msg.length() + 1);   ByteArray bob_enc_msg = encrypt(bob_msg_buffer, bob_aes_key);   \/\/ \u0418 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c\u0443 \u043a\u0430\u043d\u0430\u043b\u0443 \u0410\u043b\u0438\u0441\u0435      \/\/ \u0410\u043b\u0438\u0441\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0438 \u0434\u0435\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435   ByteArray alice_recived_msg = decrypt(bob_enc_msg, alice_aes_key);   std::cout &lt;&lt; \"Bob: \" &lt;&lt; (char*)alice_recived_msg.begin() &lt;&lt; '\\n';      \/\/ \u0411\u043e\u0431 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0438 \u0434\u0435\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435   ByteArray bob_recived_msg = decrypt(alice_enc_msg, bob_aes_key);   std::cout &lt;&lt; \"Alice: \" &lt;&lt; (char*)bob_recived_msg.begin() &lt;&lt; '\\n';    return 0; }<\/code><\/pre>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 <a href=\"https:\/\/github.com\/gbytegear\/ECDH_AES256\" rel=\"noopener noreferrer nofollow\">\u044d\u0442\u043e\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 GitHub<\/a>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/591129\/\"> https:\/\/habr.com\/ru\/articles\/591129\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u0440\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442-\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0421++ \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438. \u042f \u0441\u0440\u0430\u0437\u0443 \u043e\u0431\u0440\u0430\u0442\u0438\u043b \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0435\u0441\u044f \u0432 TLS 1.3. \u041e\u043f\u0443\u0441\u0442\u0438\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e TLS-\u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u0438 \u0432\u0437\u044f\u0432 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0430\u0441\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0437\u0430 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u044f \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043b \u043a \u0440\u0430\u0431\u043e\u0442\u0435. \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0432\u044b\u0438\u0441\u043a\u0438\u0432\u0430\u0442\u044c \u0432 \u0432\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445(\u043e\u0442 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 OpenSSL, \u0434\u043e \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043d\u0430 stackoverflow), \u0430 \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0434\u0430\u0436\u0435 \u0434\u043e\u0434\u0443\u043c\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0441\u043a\u0440\u0435\u043f\u0438\u0442\u044c \u043a\u0443\u0441\u043a\u0438 \u043a\u043e\u0434\u0430 \u0438\u0437 \u044d\u0442\u0438\u0445 \u0441\u0430\u043c\u044b\u0445 \u0440\u0430\u0437\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0443\u043c\u0430\u043d\u043d\u043e\u0433\u043e, \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e, \u0441 \u0446\u0435\u043b\u044c\u044e \u043f\u043e\u043c\u043e\u0447\u044c \u0442\u0435\u043c \u043a\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0448\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0432\u044f\u0437\u043a\u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9F%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB_%D0%94%D0%B8%D1%84%D1%84%D0%B8_%E2%80%94_%D0%A5%D0%B5%D0%BB%D0%BB%D0%BC%D0%B0%D0%BD%D0%B0_%D0%BD%D0%B0_%D1%8D%D0%BB%D0%BB%D0%B8%D0%BF%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D0%BA%D1%80%D0%B8%D0%B2%D1%8B%D1%85\" rel=\"noopener noreferrer nofollow\">\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 \u0414\u0438\u0444\u0444\u0438-\u0425\u0435\u043b\u043b\u043c\u0430\u043d \u043d\u0430 \u044d\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043a\u0440\u0438\u0432\u044b\u0445<\/a> \u0438 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/AES_(%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82_%D1%88%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)\" rel=\"noopener noreferrer nofollow\">\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u043e\u0433\u043e \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f AES 256<\/a> \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 OpenSSL \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 ECDH<\/h2>\n<p>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code class=\"cpp\">#ifndef SECURITY_HPP #define SECURITY_HPP  #include &lt;openssl\/ecdh.h> #include \"byte_array.hpp\"  namespace security {  \/**  * @brief AES256 key and initialization vector  *\/ struct AES_t {   uint8_t key[32] = {     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0,0,0,0,0,     0,0   };   uint8_t init_vector[16] = {     0,0,0,0,0,0,0,0,0,0,     0,0,0,0,0,0   };   bool isEmpty() const {       static const AES_t empty_aes;       return !std::memcmp(this, &amp;empty_aes, sizeof (AES_t));   }   void clear() {*this = AES_t();}   AES_t() = default;   AES_t(ByteArray data) {     *this = *reinterpret_cast&lt;AES_t*>(data.begin());   } };  \/\/ ECDH \/**  * @brief Generate ECDH key pair  * @return ECDH key pair  *\/ EVP_PKEY* genKey();  \/**  * @brief Free key memory  * @param key  *\/ void freeKey(EVP_PKEY* key);  \/**  * @brief Extract public key from key pair  * @param key_pair  * @return ByteArray with public key  *\/ ByteArray extractPublicKey(EVP_PKEY* key_pair);  \/**  * @brief Extract private key from key pair  * @param key_pair  * @return ByteArray with private key  *\/ ByteArray extractPrivateKey(EVP_PKEY* key_pair);  \/**  * @brief Conver ByteArrays to key pair  * @param priv_key_raw  * @param pub_key_raw  * @return ECDH key pair  *\/ EVP_PKEY* getKeyPair(ByteArray priv_key_raw, ByteArray pub_key_raw);  \/**  * @brief Get AES256 key and initialization vector from ECDH keys  * @param peer_key - public key from other side  * @param key_pair - private key from this side  * @return AES256 key and initialization vector  *\/ AES_t getSecret(ByteArray peer_key, EVP_PKEY* key_pair);  \/\/ AES256 \/**  * @brief Encrypt message  * @param plain_text  * @param aes_struct  * @return Cyphertext  *\/ ByteArray encrypt(ByteArray plain_text, AES_t aes_struct);  \/**  * @brief Decrypt message  * @param ciphertext  * @param aes_struct  * @return plain_text  *\/ ByteArray decrypt(ByteArray ciphertext, AES_t aes_struct);  \/** * @brief Encode data with base64 * @param decoded * @return *\/ ByteArray encodeBase64(ByteArray decoded);  \/** * @brief Decode base64 data * @param encoded * @return *\/ ByteArray decodeBase64(ByteArray encoded);  }  #endif \/\/ SECURITY_HPP <\/code><\/pre>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043d\u0438\u0436\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 OpenSSL \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0443\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<pre><code class=\"cpp\">\/\/ \u0444\u0430\u0439\u043b security.cpp #include \"security.hpp\"  #include &lt;openssl\/conf.h> #include &lt;openssl\/err.h> \/\/ EVP #include &lt;openssl\/evp.h> \/\/ AES #include &lt;openssl\/aes.h> \/\/ ECDH #include &lt;openssl\/ec.h> #include &lt;openssl\/pem.h>  #include &lt;stdexcept>  \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0448\u0438\u0431\u043e\u043a void handleErrors() {   ERR_print_errors_fp(stderr);   throw std::runtime_error(\"Security error\"); }  \/\/ \u041d\u0438\u0436\u0435\u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0437\u0434\u0435\u0441\u044c<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u0433\u0435\u043d\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u044b \u043a\u043b\u044e\u0447\u0435\u0439 ECDH. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 ECDH \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 OpenSSL &#8212; <a href=\"https:\/\/wiki.openssl.org\/index.php\/EVP\" rel=\"noopener noreferrer nofollow\">EVP<\/a>.<\/p>\n<pre><code class=\"cpp\">EVP_PKEY* security::genKey() {   EVP_PKEY* key_pair = nullptr;\/\/ \u041a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u043f\u0430\u0440\u0430   EVP_PKEY_CTX* param_gen_ctx = nullptr; \/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432   EVP_PKEY_CTX* key_gen_ctx = nullptr;\/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043b\u044e\u0447\u0430   EVP_PKEY* params= nullptr;\/\/ \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u043b\u044e\u0447\u0430    \/\/ \u0412\u044b\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 EC-\u043a\u043b\u044e\u0447\u0430   if(!(param_gen_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) handleErrors();   \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 EC-\u043a\u043b\u044e\u0447\u0430   if(!EVP_PKEY_paramgen_init(param_gen_ctx)) handleErrors();    \/\/ \u0417\u0430\u0434\u0430\u0451\u043c \u044d\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u043a\u0443\u044e \u043a\u0440\u0438\u0432\u0443\u044e prime256v1   if(!EVP_PKEY_CTX_set_ec_paramgen_curve_nid(param_gen_ctx, NID_X9_62_prime256v1))     handleErrors();    \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b   if(!EVP_PKEY_paramgen(param_gen_ctx, &amp;params)) handleErrors();    \/\/ \u0412\u044b\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 EC-\u043a\u043b\u044e\u0447\u0430   if(!(key_gen_ctx = EVP_PKEY_CTX_new(params, nullptr))) handleErrors();   \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 EC-\u043a\u043b\u044e\u0447\u0430   if(!EVP_PKEY_keygen_init(key_gen_ctx)) handleErrors();   \/\/ \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043a\u043b\u044e\u0447   if(!EVP_PKEY_keygen(key_gen_ctx, &amp;key_pair)) handleErrors();    \/\/ \u0412\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432   EVP_PKEY_CTX_free(param_gen_ctx);   \/\/ \u0412\u044b\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043b\u044e\u0447\u0430   EVP_PKEY_CTX_free(key_gen_ctx);   \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043f\u0430\u0440\u044b   return key_pair; }<\/code><\/pre>\n<h2>\u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u043b\u044e\u0447\u0435\u0439 ECDH \u0438\u0437 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043f\u0430\u0440\u044b EVP_PKEY* \u0432 &#171;\u0441\u044b\u0440\u043e\u0439 \u0431\u0443\u0444\u0444\u0435\u0440&#187;<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043f\u043e \u0441\u0435\u0442\u0438 \u0438\u043b\u0438 \u0436\u0435 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u043a\u0430\u043a \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0438 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438\u0437 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044f \u043d\u0430 EVP_PKEY.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u043c\u044b \u0441 C++ \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u044b\u0440\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>std::vector&lt;uint8_t><\/code> \u0438\u043b\u0438 \u043a\u043b\u0430\u0441\u0441 \u043d\u0430 \u043f\u043e\u0434\u043e\u0431\u0438\u0438 \u043d\u0438\u0436\u0435\u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e:<\/p>\n<pre><code class=\"cpp\">\/\/ \u0424\u0430\u0439\u043b byte_array.hpp #ifndef BYTE_ARRAY_HPP #define BYTE_ARRAY_HPP  #include &lt;cstdint> #include &lt;cstring> #include &lt;utility> #include &lt;new> #include &lt;malloc.h>  class ByteArray {   uint8_t* byte_array = nullptr;   uint64_t _length = 0;   public:   typedef uint8_t* iterator;   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e   ByteArray() = default;      \/\/ \u041a\u043e\u0441\u043d\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0441 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u0430\u043c\u044f\u0442\u0438   ByteArray(uint64_t length)     : byte_array(new uint8_t[length]),   _length(length) {}      \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0437 \u0441\u044b\u0440\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430   ByteArray(void* buffer, uint64_t length)     : byte_array(new uint8_t[length]),       _length(length) {         memcpy(byte_array, buffer, _length);       }      \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f   ByteArray(ByteArray&amp; other)     : byte_array(new uint8_t[other._length]),       _length(other._length) {         memcpy(byte_array, other.byte_array, _length);       }      \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f   ByteArray(ByteArray&amp;&amp; other)     : byte_array(other.byte_array),       _length(other._length) {         other.byte_array = nullptr;       }      \/\/ \u0414\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440   ~ByteArray() {if(byte_array) delete[] byte_array;}      \/\/ \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440   void resize(uint64_t new_length) {   _length = new_length;   byte_array = (uint8_t*)realloc(byte_array, _length);   }      \/\/ \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440   iterator addSize(uint64_t add) {     byte_array = (uint8_t*)realloc(byte_array, _length + add);     iterator it = byte_array + _length;     _length += add;     memset(it, 0, add);     return it;   }      \/\/ Getter \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430   inline uint64_t length() {return _length;}   \/\/ \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0432\u0437\u044f\u0442\u0438\u0435 \u0435\u043b\u0435\u043c\u0435\u043d\u0442\u0430   inline uint8_t&amp; operator[](uint64_t index) {return byte_array[index];}   \/\/ \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u0438\u044f   inline ByteArray&amp; operator=(ByteArray other) {     this->~ByteArray();     return *new(this) ByteArray(std::move(other));   }      \/\/ \u0418\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f range-based for   \/\/ for(auto byte : byte_array_object) {...}   inline iterator begin() {return byte_array;}   inline iterator end() {return byte_array + _length;} };  #endif \/\/ BYTE_ARRAY_HPP<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430:<\/p>\n<pre><code class=\"cpp\">ByteArray security::extractPublicKey(EVP_PKEY* key_pair) {   EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(key_pair);   EC_POINT* ec_point = const_cast&lt;EC_POINT*>(EC_KEY_get0_public_key(ec_key));    EVP_PKEY* public_key = EVP_PKEY_new();   EC_KEY* public_ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);    EC_KEY_set_public_key(public_ec_key, ec_point);   EVP_PKEY_set1_EC_KEY(public_key, public_ec_key);     EC_KEY *temp_ec_key = EVP_PKEY_get0_EC_KEY(public_key);    if(temp_ec_key == NULL) handleErrors();    const EC_GROUP* group = EC_KEY_get0_group(temp_ec_key);   point_conversion_form_t form = EC_GROUP_get_point_conversion_form(group);    unsigned char* pub_key_buffer;   size_t length = EC_KEY_key2buf(temp_ec_key, form, &amp;pub_key_buffer, NULL);   if(!length) handleErrors();   ByteArray data(pub_key_buffer, length);    OPENSSL_free(pub_key_buffer);   EVP_PKEY_free(public_key);   EC_KEY_free(ec_key);   EC_KEY_free(public_ec_key);   EC_POINT_free(ec_point);    return data; }<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430:<\/p>\n<pre><code class=\"cpp\">ByteArray security::extractPrivateKey(EVP_PKEY* key_pair) {   EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(key_pair);   const BIGNUM* ec_priv = EC_KEY_get0_private_key(ec_key);   int length = BN_bn2mpi(ec_priv, nullptr);   ByteArray data(length);   BN_bn2mpi(ec_priv, data.begin());   return data; }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u044b \u043a\u043b\u044e\u0447\u0435\u0439 EVP \u0438\u0437 \u0434\u0432\u0443\u0445 &#171;\u0441\u044b\u0440\u044b\u0445 \u0431\u0443\u0444\u0435\u0440\u043e\u0432&#187; \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439:<\/p>\n<pre><code class=\"cpp\">EVP_PKEY* security::getKeyPair(ByteArray priv_key_raw, ByteArray pub_key_raw) {   EVP_PKEY* key_pair = EVP_PKEY_new();   EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);    const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);   EC_POINT* ec_point = EC_POINT_new(ec_group);   EC_POINT_oct2point(ec_group, ec_point, pub_key_raw.begin(), pub_key_raw.length(), nullptr);   EC_KEY_set_public_key(ec_key, ec_point);   EC_POINT_free(ec_point);    BIGNUM* priv = BN_mpi2bn(priv_key_raw.begin(), priv_key_raw.length(), nullptr);   EC_KEY_set_private_key(ec_key, priv);   BN_free(priv);    EVP_PKEY_set1_EC_KEY(key_pair, ec_key);   EC_KEY_free(ec_key);   return key_pair; }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u043a\u043b\u044e\u0447\u0435\u0439 \u043d\u0435 \u0432 \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u043c, \u0430 \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0444\u0444\u0435\u0440 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438 base64 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 OpenSSL:<\/p>\n<pre><code class=\"cpp\">\/\/ \u0417\u0430\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 base64 ByteArray security::encodeBase64(ByteArray decoded) {   ByteArray encoded((4*((decoded.length()+2)\/3)) + 1);   EVP_EncodeBlock(encoded.begin(),<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-409975","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/409975","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=409975"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/409975\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=409975"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=409975"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=409975"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}