{"id":479334,"date":"2026-05-11T16:00:04","date_gmt":"2026-05-11T16:00:04","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=479334"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=479334","title":{"rendered":"\u042f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b Double Ratchet \u0432 React Native \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440\u0435. \u0420\u0430\u0437\u0431\u043e\u0440 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0438 \u043a\u043e\u0434\u0430"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<blockquote>\n<p>\u0423\u0440\u043e\u0432\u0435\u043d\u044c: senior \u00b7 \u043d\u0443\u0436\u043d\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 (AES, ECDH, KDF) \u0421\u0442\u0435\u043a: React Native, Expo SDK 54, WebCrypto API, expo-secure-store, TypeScript \u0427\u0442\u043e \u0432\u043d\u0443\u0442\u0440\u0438: \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 Signal Double Ratchet, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 ~300 \u0441\u0442\u0440\u043e\u043a, \u0433\u0440\u0430\u0431\u043b\u0438, \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0438 \u043f\u0440\u043e \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u043e\u0442 \u043a\u0430\u043d\u043e\u043d\u0430<\/p>\n<\/blockquote>\n<h4>\u0417\u0430\u0447\u0435\u043c \u043c\u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u0441\u044f Double Ratchet<\/h4>\n<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u043e \u0442\u0440\u0451\u0445\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043a\u044d\u0448 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u044f \u0443\u0436\u0435 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u044e \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440 ONEMIX \u043d\u0430 React Native. \u0411\u0430\u0437\u043e\u0432\u043e\u0435 E2E \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0435: ECDH P-256 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0435, AES-GCM \u0434\u043b\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0438\u043c \u0441\u0435\u043a\u0440\u0435\u0442\u043e\u043c. \u042d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u043e\u0434\u043d\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443: <strong>\u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442 \u043e\u0434\u0438\u043d \u043d\u0430 \u0432\u0441\u044e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0443<\/strong>. \u0415\u0441\u043b\u0438 \u0443 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u0441\u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0438\u0440\u0443\u044e\u0442 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u2014 \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0437\u0430 \u0432\u0441\u0451 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442.<\/p>\n<p>\u042d\u0442\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c Perfect Forward Secrecy (PFS). \u0418 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0432 \u0440\u0443\u043a\u0438 \u043f\u043e\u043f\u0430\u0434\u0451\u0442 \u0442\u0432\u043e\u0439 \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u0447\u0435\u0440\u0435\u0437 \u0433\u043e\u0434, \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0443 \u0438\u0437 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0433\u043e\u0434\u0430. WhatsApp, Signal, \u0438 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 Telegram \u0434\u0430\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0434\u0440\u0443\u0433\u0443\u044e \u0441\u0445\u0435\u043c\u0443 \u2014 Double Ratchet \u2014 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043a\u043b\u044e\u0447\u0438 <strong>\u043f\u0435\u0440\u0435\u0438\u0437\u0431\u0440\u0435\u0442\u0430\u0435\u0442<\/strong> \u0437\u0430\u043d\u043e\u0432\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438. \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u044e\u0442 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043b\u044e\u0431\u043e\u0439 \u043a\u043b\u044e\u0447 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u0438\u043d \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0438 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0430\u0446\u0438\u044f \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0434\u0430\u0432\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0438 \u043a \u043f\u0440\u043e\u0448\u043b\u043e\u043c\u0443, \u043d\u0438 \u043a \u0431\u0443\u0434\u0443\u0449\u0435\u043c\u0443.<\/p>\n<p>\u042f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b Double Ratchet \u0441 \u043d\u0443\u043b\u044f \u0434\u043b\u044f ONEMIX. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443:<\/p>\n<ul>\n<li>\n<p>\u041a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0438\u0434\u0435\u0438 (\u0431\u0435\u0437 \u043c\u0430\u0442\u0430\u043d\u0430).<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 ~300 \u0441\u0442\u0440\u043e\u043a TypeScript \u043f\u043e\u0432\u0435\u0440\u0445 WebCrypto API.<\/p>\n<\/li>\n<li>\n<p>\u0413\u0434\u0435 \u044f \u043e\u0442\u0441\u0442\u0443\u043f\u0438\u043b \u043e\u0442 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e Signal Protocol \u0438 \u043f\u043e\u0447\u0435\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p>\u0413\u0440\u0430\u0431\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0441\u043e\u0431\u0440\u0430\u043b \u043f\u043e \u0434\u043e\u0440\u043e\u0433\u0435.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0421\u0440\u0430\u0437\u0443 \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0430 \u043f\u0440\u043e &#171;production-grade&#187;.<\/strong> \u042f \u0434\u0435\u043b\u0430\u044e \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440 \u043e\u0434\u0438\u043d, \u043c\u043e\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0448\u043b\u0430 \u043c\u043e\u0438 \u0442\u0435\u0441\u0442\u044b, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0430\u0443\u0434\u0438\u0442 NCC Group \u0438 \u043d\u0435 Trail of Bits. \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0435\u0437\u0443\u043f\u0440\u0435\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u2014 \u0431\u0435\u0440\u0438\u0442\u0435 <a href=\"https:\/\/github.com\/signalapp\/libsignal-protocol-typescript\" rel=\"noopener noreferrer nofollow\">libsignal-protocol-typescript<\/a> \u0438\u043b\u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0438. \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0432\u043d\u0443\u0442\u0440\u0438 \u0438 \u043a\u0430\u043a \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0443\u043a\u0430\u043c\u0438. \u041f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e, \u0447\u0435\u043c \u0442\u044b \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0448\u044c\u0441\u044f. \u0423\u0447\u0438\u0442\u044c\u0441\u044f \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0441\u0430\u043c\u043e\u043c\u0443, \u0440\u0430\u0437\u0431\u0438\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0438 \u0441\u043e\u0431\u0440\u0430\u0432 \u0441\u043d\u043e\u0432\u0430.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 1. \u0418\u0434\u0435\u044f Double Ratchet \u0437\u0430 5 \u043c\u0438\u043d\u0443\u0442<\/h3>\n<p>\u0423 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0434\u0432\u0430 &#171;\u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a\u0430&#187; (\u043e\u0442\u0441\u044e\u0434\u0430 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435). \u041a\u0430\u0436\u0434\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a \u2014 \u044d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043f\u0435\u0440\u0451\u0434: \u043f\u043e\u0441\u043b\u0435 \u0449\u0435\u043b\u0447\u043a\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0437\u043d\u0430\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0435\u0433\u043e\u0434\u043d\u044f, \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u0447\u0435\u0440\u0430\u0448\u043d\u0435\u0435.<\/p>\n<p><strong>\u0421\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a (Symmetric Ratchet).<\/strong> \u041d\u0430 \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0431\u0435\u0440\u0451\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u0439 &#171;chain key&#187; (CK), \u0438 \u0438\u0437 \u043d\u0435\u0433\u043e KDF \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0434\u0432\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f: \u043d\u043e\u0432\u044b\u0439 chain key \u0438 message key (MK). MK \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0434\u043b\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f. CK \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u2014 \u0441\u0442\u0430\u0440\u044b\u0439 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442 CK \u0441\u0435\u0439\u0447\u0430\u0441, \u043e\u043d \u0441\u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 MK \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043d\u043e \u043d\u0435 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e KDF \u2014 \u043e\u0434\u043d\u043e\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044f\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f.<\/p>\n<pre><code>CK_0 \u2192 KDF \u2192 (CK_1, MK_0)    # \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 0 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e MK_0CK_1 \u2192 KDF \u2192 (CK_2, MK_1)    # \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 1 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e MK_1CK_2 \u2192 KDF \u2192 (CK_3, MK_2)    # \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 2 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e MK_2<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0434\u0430\u0451\u0442 <strong>forward secrecy \u0432 \u043e\u0434\u043d\u0443 \u0441\u0442\u043e\u0440\u043e\u043d\u0443<\/strong>: \u0437\u0430\u0445\u0432\u0430\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0435 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0448\u043b\u043e\u0435. \u041d\u043e \u043d\u0435 \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u0431\u0443\u0434\u0443\u0449\u0435\u0439 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0430\u0446\u0438\u0438 \u0432 \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u2014 \u0435\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0437\u043d\u0430\u0435\u0442 CK_2, \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c CK_3, CK_4 \u0438 \u0432\u0441\u0451 \u0447\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<p><strong>DH-\u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a (DH Ratchet).<\/strong> \u0420\u0435\u0448\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043a\u043e\u0433\u0434\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u043e\u043b\u044f\u043c\u0438 (\u0410\u043b\u0438\u0441\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430, \u0411\u043e\u0431 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442), \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u0430\u044f \u043f\u0430\u0440\u0430 DH-\u043a\u043b\u044e\u0447\u0435\u0439. \u0418\u0437 ECDH \u0441 \u043d\u043e\u0432\u044b\u043c\u0438 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f <strong>\u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442<\/strong>, \u0438 \u0438\u0437 \u043d\u0435\u0433\u043e HKDF \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043d\u043e\u0432\u044b\u0439 root key (RK) \u0438 \u043d\u043e\u0432\u044b\u0439 chain key \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438. \u042d\u0442\u043e\u0442 \u0448\u0430\u0433 &#171;\u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442&#187; \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a \u0441 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0439 \u043e\u0442 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0439 \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u043e\u0439. \u042d\u0442\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <strong>post-compromise security<\/strong> \u0438\u043b\u0438 <strong>break-in recovery<\/strong>: \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u043b \u043f\u043e\u043b\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043f\u043e\u0441\u043b\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e DH-\u0448\u0430\u0433\u0430 \u043e\u043d \u0441\u043d\u043e\u0432\u0430 \u0432 \u043d\u0435\u0432\u0435\u0434\u0435\u043d\u0438\u0438.<\/p>\n<p>\u0412\u043c\u0435\u0441\u0442\u0435 \u043e\u043d\u0438 \u0434\u0430\u044e\u0442 \u0442\u043e \u0441\u0430\u043c\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e Signal: <strong>\u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0438 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445, \u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u043f\u043e\u0441\u043b\u0435 DH-\u0448\u0430\u0433\u0430<\/strong>.<\/p>\n<p>\u0418 \u043e\u0434\u0438\u043d \u0442\u043e\u043d\u043a\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u043d\u0435 \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443. \u0415\u0441\u043b\u0438 \u0410\u043b\u0438\u0441\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0430 5 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0430 \u0443 \u0411\u043e\u0431\u0430 \u043f\u0440\u0438\u0448\u043b\u0438 #1, #3, #5 (\u0430 #2 \u0438 #4 \u0437\u0430\u0441\u0442\u0440\u044f\u043b\u0438 \u0432 Push-\u043d\u043e\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u0445), \u0411\u043e\u0431 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0435\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c #3 \u043d\u0435 \u0437\u043d\u0430\u044f #2. \u042d\u0442\u043e \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <strong>skipped message keys<\/strong>: \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 #3 \u0411\u043e\u0431 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 MK \u0434\u043b\u044f #2 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0435\u0433\u043e \u0432 <code>MKSKIPPED<\/code>. \u041a\u043e\u0433\u0434\u0430 #2 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442, \u0411\u043e\u0431 \u0434\u043e\u0441\u0442\u0430\u0451\u0442 MK \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0430\u0435\u0442. \u0420\u0430\u0437\u043c\u0435\u0440 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d (MAX_SKIP) \u2014 \u0438\u043d\u0430\u0447\u0435 \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u0433 \u0431\u044b \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0441 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u044b \u043a\u043b\u044e\u0447\u0435\u0439.<\/p>\n<p>\u042d\u0442\u043e\u0433\u043e \u0445\u0432\u0430\u0442\u0438\u0442 \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u043a\u043e\u0434.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 2. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/h3>\n<p>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Double Ratchet \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0447\u0430\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0443 \u043c\u0435\u043d\u044f \u0442\u0430\u043a:<\/p>\n<pre><code class=\"typescript\">export interface RatchetState {  \/\/ DH \u043f\u0430\u0440\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f  DHs_pub:  string;   \/\/ base64 raw  DHs_priv: string;   \/\/ base64 pkcs8  \/\/ DH \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430  DHr:      string | null;  \/\/ \u041a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043a\u043b\u044e\u0447  RK:       string;   \/\/ base64, 32 \u0431\u0430\u0439\u0442\u0430  \/\/ \u0426\u0435\u043f\u043e\u0447\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438\/\u043f\u0440\u0438\u0451\u043c\u0430  CKs:      string | null;  \/\/ sending chain key  CKr:      string | null;  \/\/ receiving chain key  \/\/ \u0421\u0447\u0451\u0442\u0447\u0438\u043a\u0438  Ns:       number;   \/\/ sent messages counter  Nr:       number;   \/\/ received messages counter  PN:       number;   \/\/ prev sending chain length  \/\/ Skipped message keys (\u0434\u043b\u044f out-of-order)  MKSKIPPED: Record&lt;string, string&gt;; \/\/ \"pubkey:N\" \u2192 base64 key}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u043c\u0435\u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u0437\u044f\u0442\u044b \u043f\u0440\u044f\u043c\u043e \u0438\u0437 <a href=\"https:\/\/signal.org\/docs\/specifications\/doubleratchet\/\" rel=\"noopener noreferrer nofollow\">\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 Signal Double Ratchet<\/a>. \u042d\u0442\u043e \u043d\u0435 \u0438\u0437 \u044d\u0441\u0442\u0435\u0442\u0438\u043a\u0438 \u2014 \u044d\u0442\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0447\u0442\u0435\u043d\u0438\u0435 \u0441\u043f\u0435\u043a\u0438 \u0440\u044f\u0434\u043e\u043c \u0441 \u043a\u043e\u0434\u043e\u043c, \u0438 \u043b\u044e\u0431\u043e\u0439 \u043a\u0442\u043e \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0443\u0437\u043d\u0430\u0451\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0430\u0437\u0443.<\/p>\n<p>\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u044e \u044d\u0442\u043e \u0432\u0441\u0451 \u0432 <code>expo-secure-store<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 iOS Keychain \u0438 Android Keystore. \u042d\u0442\u043e \u043d\u0435 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u0430\u044f \u043a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0437\u0430\u0449\u0438\u0442\u0430 (Keychain \u043d\u0435 \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u0440\u0443\u0442\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430), \u043d\u043e \u044d\u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u0447\u0435\u043c AsyncStorage, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043b\u0435\u0436\u0438\u0442 plain \u0432 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u041e\u0434\u0438\u043d ratchet-state \u043d\u0430 \u0447\u0430\u0442: <code>onemix_ratchet_${chatId}<\/code>. \u0415\u0441\u043b\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f 50 \u0447\u0430\u0442\u043e\u0432 \u2014 50 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 ratchet-state.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 3. \u041a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b<\/h3>\n<p>\u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b \u2014 \u0447\u0435\u0440\u0435\u0437 <code>crypto.subtle<\/code> (WebCrypto API). \u0412 Expo SDK 54 \u043e\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/github.com\/margelo\/react-native-quick-crypto\" rel=\"noopener noreferrer nofollow\">react-native-quick-crypto<\/a> \u0438\u043b\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 polyfill&#8217;\u044b. \u042d\u0442\u043e \u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043d\u0435 \u043d\u0430 JS, \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0434\u0430\u0436\u0435 \u043d\u0430 \u0431\u044e\u0434\u0436\u0435\u0442\u043d\u044b\u0445 Android.<\/p>\n<p><strong>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f ECDH-\u043f\u0430\u0440\u044b:<\/strong><\/p>\n<pre><code class=\"typescript\">async function generateDHPair(): Promise&lt;{ pub: string; priv: string }&gt; {  const kp = await crypto.subtle.generateKey(    { name: \"ECDH\", namedCurve: \"P-256\" }, true, [\"deriveKey\", \"deriveBits\"]  );  const pub  = await crypto.subtle.exportKey(\"raw\",   kp.publicKey);  const priv = await crypto.subtle.exportKey(\"pkcs8\", kp.privateKey);  return { pub: bufToBase64(pub), priv: bufToBase64(priv) };}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>\u0421\u0440\u0430\u0437\u0443 \u0432\u0430\u0436\u043d\u0430\u044f \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0430.<\/strong> \u041a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 Signal Protocol \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <strong>Curve25519<\/strong> (X25519 \u0434\u043b\u044f ECDH, Ed25519 \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439). Curve25519 \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 \u043f\u0435\u0440\u0435\u0434 P-256: \u043f\u0440\u043e\u0449\u0435 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 side-channel \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0437\u0430\u0432\u0435\u0434\u043e\u043c\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b (\u0434\u043b\u044f P-256 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u0437\u044f\u0442\u044b \u0438\u0437 NIST \u0438 \u0435\u0441\u0442\u044c <a href=\"https:\/\/safecurves.cr.yp.to\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u043e\u043c\u043d\u0435\u043d\u0438\u044f<\/a> \u0432 \u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0441\u0442\u0438), \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043d\u0430 \u0431\u044e\u0434\u0436\u0435\u0442\u043d\u043e\u043c \u0436\u0435\u043b\u0435\u0437\u0435.<\/p>\n<p>\u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e <strong>P-256, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e WebCrypto API \u0432 RN \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 Curve25519 \u043d\u0430\u0442\u0438\u0432\u043d\u043e<\/strong>. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c X25519 \u0432 \u0447\u0438\u0441\u0442\u043e\u043c JS \u043c\u043e\u0436\u043d\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 <code>@noble\/curves<\/code>), \u043d\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e crypto.subtle \u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u0443\u0434\u0438\u0442\u0430 \u0441\u0430\u043c\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u042f \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043b \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 P-256 \u0446\u0435\u043d\u043e\u0439 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u043e\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u043d\u0435 Signal Protocol, \u0430 Double Ratchet \u043d\u0430 P-256. \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 threat models \u044d\u0442\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e. \u0415\u0441\u043b\u0438 \u0432\u0430\u0448\u0430 threat model \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 NSA-level \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u0438\u043a\u0430 \u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e \u043f\u043e\u0434\u0441\u0430\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 NIST \u2014 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u0435 \u043d\u0430 Curve25519 \u0447\u0435\u0440\u0435\u0437 <code>@noble\/curves<\/code> \u0438\u043b\u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0438.<\/p>\n<p><strong>ECDH:<\/strong><\/p>\n<pre><code class=\"typescript\">async function dh(privB64: string, pubB64: string): Promise&lt;ArrayBuffer&gt; {  const privKey = await crypto.subtle.importKey(    \"pkcs8\", base64ToBuf(privB64),    { name: \"ECDH\", namedCurve: \"P-256\" }, false, [\"deriveBits\"]  );  const pubKey = await crypto.subtle.importKey(    \"raw\", base64ToBuf(pubB64),    { name: \"ECDH\", namedCurve: \"P-256\" }, false, []  );  return crypto.subtle.deriveBits({ name: \"ECDH\", public: pubKey }, privKey, 256);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>HKDF \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u043d\u044b\u0445 KDF \u2014 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0438 \u0446\u0435\u043f\u043e\u0447\u043d\u043e\u0433\u043e:<\/strong><\/p>\n<pre><code class=\"typescript\">async function hkdf(input: ArrayBuffer, salt: string, info: string, length = 32): Promise&lt;ArrayBuffer&gt; {  const key  = await importHKDFKey(input);  return crypto.subtle.deriveBits(    { name: \"HKDF\", hash: \"SHA-256\", salt: enc.encode(salt), info: enc.encode(info) },    key, length * 8  );}\/** KDF \u0434\u043b\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430: \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 [\u043d\u043e\u0432\u044b\u0439 RK, chain key] *\/async function kdfRK(rk: ArrayBuffer, dhOut: ArrayBuffer): Promise&lt;[ArrayBuffer, ArrayBuffer]&gt; {  const combined = await hkdf(dhOut, dec.decode(rk), \"onemix-ratchet-rk\", 64);  return [combined.slice(0, 32), combined.slice(32)];}\/** KDF \u0434\u043b\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0438: \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 [\u043d\u043e\u0432\u044b\u0439 CK, message key] *\/async function kdfCK(ck: ArrayBuffer): Promise&lt;[ArrayBuffer, ArrayBuffer]&gt; {  const [ckBytes, mkBytes] = await Promise.all([    hkdf(ck, \"onemix-chain-key\", \"onemix-ck\", 32),    hkdf(ck, \"onemix-msg-key\",   \"onemix-mk\", 32),  ]);  return [ckBytes, mkBytes];}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0443\u0442 \u0435\u0441\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u043d\u0430 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u044c, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0434\u043e \u0447\u0435\u0441\u0442\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c. \u0412 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u043c Signal Double Ratchet <code>kdfCK<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <strong>HMAC \u0441 \u0434\u0432\u0443\u043c\u044f \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430\u043c\u0438<\/strong> (0x01 \u0438 0x02 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 input), \u0430 \u043d\u0435 \u0434\u0432\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 HKDF-\u0432\u044b\u0437\u043e\u0432\u0430. \u042d\u0442\u043e \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u0430\u044f \u043f\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f, \u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u0430\u044f. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0434\u0432\u0435 HKDF-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0443 crypto.subtle \u043d\u0430\u0442\u0438\u0432\u043d\u043e \u0435\u0441\u0442\u044c HKDF, \u043d\u043e \u043d\u0435\u0442 \u043f\u0440\u044f\u043c\u043e\u0433\u043e HMAC-based ratchet primitive \u2014 \u0430 \u0437\u0430\u0432\u043e\u0434\u0438\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u043d\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e HMAC \u043f\u043e\u0432\u0435\u0440\u0445 HKDF \u043c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c. \u0421\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0442\u043e\u0442 \u0436\u0435: \u0434\u0432\u0430 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 32-\u0431\u0430\u0439\u0442\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0430 \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0445\u043e\u0434\u0430.<\/p>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e, <code>kdfRK<\/code> \u0432 \u043a\u0430\u043d\u043e\u043d\u0435 \u2014 \u044d\u0442\u043e HKDF \u0441 \u0434\u0432\u0443\u043c\u044f \u0432\u044b\u0445\u043e\u0434\u0430\u043c\u0438 (RK || CK) \u0434\u043b\u0438\u043d\u044b 64 \u0431\u0430\u0439\u0442\u0430, \u0440\u0430\u0437\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043f\u043e\u043b\u0430\u043c. \u042d\u0442\u043e \u044f <strong>\u0441\u0434\u0435\u043b\u0430\u043b \u0432 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438<\/strong>.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 4. \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0410\u043b\u0438\u0441\u0430 \u0438 \u0411\u043e\u0431 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0443, \u0443 \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u0435\u0440\u0432\u0443\u044e \u0446\u0435\u043f\u043e\u0447\u043a\u0443. \u0412 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u043c Signal \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/signal.org\/docs\/specifications\/x3dh\/\" rel=\"noopener noreferrer nofollow\">X3DH<\/a> \u2014 Triple Diffie-Hellman, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u0443\u0435\u0442 identity keys, signed prekeys \u0438 one-time prekeys \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f shared secret \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 replay.<\/p>\n<p>\u042f <strong>\u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u043f\u043e\u043b\u043d\u044b\u0439 X3DH<\/strong>. \u0423 \u043c\u0435\u043d\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043e\u0431\u043c\u0435\u043d: \u043e\u0434\u0438\u043d ECDH \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u044b\u043c\u0438 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u043e\u0431\u0435\u0438\u0445 \u0441\u0442\u043e\u0440\u043e\u043d. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0447\u0442\u043e \u043c\u043e\u0439 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 shared secret \u0443\u044f\u0437\u0432\u0438\u043c \u043a replay (\u0435\u0441\u043b\u0438 \u043a\u0442\u043e-\u0442\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u043b \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0410\u043b\u0438\u0441\u044b \u0438 \u0448\u0435\u0441\u0442\u044c \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u0441\u043f\u0443\u0441\u0442\u044f \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0451\u043b \u0435\u0433\u043e \u2014 \u0411\u043e\u0431 \u0435\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u0442). \u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u043c\u0438\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0411\u043e\u0431 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 chatId \u0438 \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u0443\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. \u041d\u043e \u044d\u0442\u043e \u0441\u043b\u0430\u0431\u0435\u0435 X3DH.<\/p>\n<pre><code class=\"typescript\">export async function initSender(  chatId: string,  bobPublicKeyB64: string,  sharedSecretB64: string,): Promise&lt;RatchetState&gt; {  const DHs = await generateDHPair();  const dhOut = await dh(DHs.priv, bobPublicKeyB64);  const [RK, CKs] = await kdfRK(base64ToBuf(sharedSecretB64), dhOut);  const state: RatchetState = {    DHs_pub: DHs.pub, DHs_priv: DHs.priv,    DHr: bobPublicKeyB64,    RK: bufToBase64(RK), CKs: bufToBase64(CKs), CKr: null,    Ns: 0, Nr: 0, PN: 0,    MKSKIPPED: {},  };  await saveState(chatId, state);  return state;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0427\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442:<\/p>\n<ol>\n<li>\n<p>\u0410\u043b\u0438\u0441\u0430 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043d\u043e\u0432\u0443\u044e ephemeral DH-\u043f\u0430\u0440\u0443 (<code>DHs_pub<\/code>, <code>DHs_priv<\/code>). \u042d\u0442\u043e \u0435\u0451 \u043f\u0435\u0440\u0432\u044b\u0439 ratchet-\u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0435\u043b\u0430\u0435\u0442 ECDH \u0441\u0432\u043e\u0435\u0439 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0441 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c \u0411\u043e\u0431\u0430 (<code>bobPublicKeyB64<\/code>) \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 <code>dhOut<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 <code>kdfRK<\/code> \u043a \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 shared secret (\u0432\u0445\u043e\u0434) \u0438 dhOut \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 <code>RK<\/code> \u0438 <code>CKs<\/code> (sending chain key).<\/p>\n<\/li>\n<\/ol>\n<p>\u0423 \u0410\u043b\u0438\u0441\u044b \u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e sending chain (<code>CKs<\/code>) \u2014 \u043e\u043d\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u0438\u0448\u0435\u0442. Receiving chain (<code>CKr<\/code>) \u043f\u043e\u043a\u0430 null. \u0411\u043e\u0431 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0435\u0440\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e: \u0432\u043e\u0437\u044c\u043c\u0451\u0442 \u0441\u0432\u043e\u0439 \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 DHs \u0410\u043b\u0438\u0441\u044b, \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0442\u043e\u0442 \u0436\u0435 dhOut (\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e ECDH: dh(a, B) = dh(b, A)), \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442 \u0442\u043e\u0442 \u0436\u0435 KDF \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u0439 <code>CKr<\/code>. \u042d\u0442\u043e \u0438 \u0435\u0441\u0442\u044c \u043c\u0430\u0433\u0438\u044f Diffie-Hellman.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 5. \u0428\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/h3>\n<p>\u042d\u0442\u043e \u0441\u0430\u043c\u0430\u044f \u043a\u043e\u0440\u043e\u0442\u043a\u0430\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0432 Double Ratchet:<\/p>\n<pre><code class=\"typescript\">export async function ratchetEncrypt(chatId: string, plaintext: string): Promise&lt;string&gt; {  let state = await loadState(chatId);  if (!state) throw new Error(\"Ratchet not initialized for \" + chatId);  if (!state.CKs) {    \/\/ \u041f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u2014 \u043d\u0443\u0436\u0435\u043d DH ratchet    if (!state.DHr) throw new Error(\"No DHr\");    const dhOut = await dh(state.DHs_priv, state.DHr);    const [RK, CKs] = await kdfRK(base64ToBuf(state.RK), dhOut);    state.RK  = bufToBase64(RK);    state.CKs = bufToBase64(CKs);  }  const [newCKs, MK] = await kdfCK(base64ToBuf(state.CKs!));  const { iv, ct }   = await aesEncrypt(MK, plaintext);  const msg: RatchetMessage = {    v: 3, dh: state.DHs_pub,    pn: state.PN, n: state.Ns,    iv, ct,  };  state.CKs = bufToBase64(newCKs);  state.Ns += 1;  await saveState(chatId, state);  return JSON.stringify(msg);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e \u0448\u0430\u0433\u0430\u043c:<\/p>\n<ol>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442 sending chain key (\u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u043d\u0430\u0448 CKs \u0441\u0431\u0440\u043e\u0441\u0438\u043b\u0441\u044f), \u0434\u0435\u043b\u0430\u0435\u043c DH-\u0448\u0430\u0433 \u0447\u0435\u0440\u0435\u0437 \u0441\u0432\u043e\u0439 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u0438 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 RK \u0438 CKs.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a: \u0438\u0437 CKs \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 CKs \u0438 message key MK.<\/p>\n<\/li>\n<li>\n<p>\u0428\u0438\u0444\u0440\u0443\u0435\u043c plaintext \u0447\u0435\u0440\u0435\u0437 AES-256-GCM \u043a\u043b\u044e\u0447\u043e\u043c MK \u0441 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c 12-\u0431\u0430\u0439\u0442\u043d\u044b\u043c IV.<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435: \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0435 \u043d\u0430\u0448 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 DHs (\u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044c \u0437\u043d\u0430\u043b, \u043d\u0443\u0436\u0435\u043d \u043b\u0438 DH-\u0448\u0430\u0433), PN (\u0434\u043b\u0438\u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u2014 \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f skipped keys \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f), N (\u043d\u043e\u043c\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0435).<\/p>\n<\/li>\n<li>\n<p>\u0421\u0434\u0432\u0438\u0433\u0430\u0435\u043c sending chain key \u0438 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0447\u0451\u0442\u0447\u0438\u043a \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<\/ol>\n<p><code>MK<\/code> \u043f\u043e\u0441\u043b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442 \u043d\u0430\u0448 telephone \u043f\u0440\u044f\u043c\u043e \u0441\u0435\u0439\u0447\u0430\u0441, \u0443 \u043d\u0435\u0433\u043e \u0431\u0443\u0434\u0435\u0442 <code>state.CKs<\/code> (\u043d\u043e\u0432\u044b\u0439, \u043f\u043e\u0441\u043b\u0435 \u0441\u0434\u0432\u0438\u0433\u0430) \u2014 \u043d\u043e \u043d\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439, \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 MK, \u0438 \u043d\u0435 plaintext.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 6. \u0420\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0430<\/h3>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0430\u043c\u0430\u044f \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0432\u043e \u0432\u0441\u0451\u043c \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0435.<\/p>\n<pre><code class=\"typescript\">export async function ratchetDecrypt(chatId: string, encryptedJson: string): Promise&lt;string&gt; {  let state = await loadState(chatId);  if (!state) throw new Error(\"Ratchet not initialized for \" + chatId);  const msg: RatchetMessage = JSON.parse(encryptedJson);  if (msg.v !== 3) throw new Error(\"Unknown ratchet version\");  \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c skipped keys  const skipKey = `${msg.dh}:${msg.n}`;  if (state.MKSKIPPED[skipKey]) {    const MK = base64ToBuf(state.MKSKIPPED[skipKey]);    delete state.MKSKIPPED[skipKey];    await saveState(chatId, state);    return aesDecrypt(MK, msg.iv, msg.ct);  }  \/\/ DH Ratchet \u0448\u0430\u0433 \u0435\u0441\u043b\u0438 \u043d\u043e\u0432\u044b\u0439 DH \u043a\u043b\u044e\u0447  if (msg.dh !== state.DHr) {    state = await skipMessageKeys(state, msg.pn);    state = await dhRatchetStep(state, msg.dh);  }  \/\/ \u041f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c out-of-order  state = await skipMessageKeys(state, msg.n);  \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c message key  const [newCKr, MK] = await kdfCK(base64ToBuf(state.CKr!));  state.CKr = bufToBase64(newCKr);  state.Nr += 1;  await saveState(chatId, state);  return aesDecrypt(MK, msg.iv, msg.ct);}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c:<\/p>\n<ol>\n<li>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u2014 \u043c\u043e\u0436\u0435\u0442, \u043c\u044b \u0443\u0436\u0435 \u043a\u043e\u0433\u0434\u0430-\u0442\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u043b\u0438 MK \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e <code>(dh, n)<\/code> \u043f\u0430\u0440\u044b \u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u043b\u0438 \u0432 <code>MKSKIPPED<\/code>. \u0415\u0441\u043b\u0438 \u0434\u0430 \u2014 \u0434\u043e\u0441\u0442\u0430\u0451\u043c, \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u043e\u0442\u0442\u0443\u0434\u0430, \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0430\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u2014 \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <code>msg.dh<\/code>. \u0415\u0441\u043b\u0438 \u043e\u043d \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u043e\u0433\u043e <code>state.DHr<\/code> \u2014 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u043b\u0441\u044f \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 ratchet-\u043a\u043b\u044e\u0447. \u041d\u0443\u0436\u0435\u043d DH-\u0448\u0430\u0433.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0434 DH-\u0448\u0430\u0433\u043e\u043c \u0432\u0430\u0436\u043d\u043e: <strong>\u0441\u043d\u0430\u0447\u0430\u043b\u0430<\/strong> \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c skipped keys \u0438\u0437 \u0441\u0442\u0430\u0440\u043e\u0439 receiving chain \u0434\u043e <a href=\"http:\/\/msg.pn\" rel=\"noopener noreferrer nofollow\"><code>msg.pn<\/code><\/a> (\u044d\u0442\u043e \u0434\u043b\u0438\u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438, \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044c \u0435\u0451 \u0437\u043d\u0430\u0435\u0442 \u0438 \u043a\u043b\u0430\u0434\u0451\u0442 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a). \u0418\u043d\u0430\u0447\u0435 \u0435\u0441\u043b\u0438 \u043a\u0442\u043e-\u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0441\u0442\u0430\u0440\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0435, \u0430 \u043e\u043d\u043e \u0434\u043e\u0433\u043e\u043d\u0438\u0442 \u043d\u0430\u0441 \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 DH-\u0448\u0430\u0433\u0430 \u2014 \u043c\u044b \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0435\u0433\u043e \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c DH-\u0448\u0430\u0433: \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c <code>CKr<\/code>, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u0443\u044e <code>DHs<\/code> \u043f\u0430\u0440\u0443, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c <code>CKs<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u043d\u043e\u0432\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u0434\u043e <code>msg.n<\/code>, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u0438\u0445 MK \u0432 <code>MKSKIPPED<\/code> \u0434\u043b\u044f \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a: \u0438\u0437 <code>CKr<\/code> \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 <code>CKr<\/code> \u0438 <code>MK<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0430\u0435\u043c.<\/p>\n<\/li>\n<\/ol>\n<p>Skipped message keys:<\/p>\n<pre><code class=\"typescript\">async function skipMessageKeys(state: RatchetState, until: number): Promise&lt;RatchetState&gt; {  if (!state.CKr) return state;  if (until - state.Nr &gt; MAX_SKIP) throw new Error(\"Too many skipped messages\");  while (state.Nr &lt; until) {    const [newCKr, MK] = await kdfCK(base64ToBuf(state.CKr));    state.MKSKIPPED[`${state.DHr}:${state.Nr}`] = bufToBase64(MK);    state.CKr = bufToBase64(newCKr);    state.Nr += 1;  }  return state;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>MAX_SKIP = 100<\/code> \u2014 \u0437\u0430\u0449\u0438\u0442\u0430 \u043e\u0442 DoS: \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u0433 \u0431\u044b \u043f\u0440\u0438\u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 N=1000000 \u0438 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0441 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0438\u043b\u043b\u0438\u043e\u043d KDF-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439. \u0421 \u043b\u0438\u043c\u0438\u0442\u043e\u043c 100 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u0432\u0435\u0440\u0433\u0430\u0435\u0442\u0441\u044f.<\/p>\n<p>\u0422\u0443\u0442 \u0435\u0441\u0442\u044c subtle bug, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u044f \u0434\u043e\u043b\u0433\u043e \u043d\u0435 \u0432\u0438\u0434\u0435\u043b, \u0438 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043b \u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439. \u0415\u0441\u043b\u0438 ratchet \u0435\u0449\u0451 \u043d\u0438 \u0440\u0430\u0437\u0443 \u043d\u0435 \u0434\u0435\u043b\u0430\u043b DH-\u0448\u0430\u0433 (initial state \u0443 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f), \u0442\u043e <code>state.DHr<\/code> \u0443\u0436\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d (\u044d\u0442\u043e \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0410\u043b\u0438\u0441\u044b \u043f\u0440\u0438 init), \u043d\u043e \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0442 \u0410\u043b\u0438\u0441\u044b \u0435\u0449\u0451 \u043d\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 skipMessageKeys \u0434\u043e\u043b\u0436\u0435\u043d \u043c\u043e\u043b\u0447\u0430 \u0432\u044b\u0439\u0442\u0438, \u0430 \u043d\u0435 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c msg.dh \u0441 DHr \u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c &#171;\u043b\u043e\u0436\u043d\u044b\u0439&#187; DH-\u0448\u0430\u0433. \u042f \u0434\u043e\u0431\u0430\u0432\u0438\u043b <code>if (!state.CKr) return state;<\/code> \u0432 \u043d\u0430\u0447\u0430\u043b\u043e \u2014 \u044d\u0442\u043e \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u0435\u0442 initial state, \u043a\u043e\u0433\u0434\u0430 receiving chain \u0435\u0449\u0451 \u043d\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 7. DH-\u0448\u0430\u0433 \u2014 \u0441\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435<\/h3>\n<pre><code class=\"typescript\">async function dhRatchetStep(state: RatchetState, header_dh: string): Promise&lt;RatchetState&gt; {  state.PN = state.Ns;  state.Ns = 0;  state.Nr = 0;  state.DHr = header_dh;  const dhOut1 = await dh(state.DHs_priv, state.DHr);  const [RK1, CKr] = await kdfRK(base64ToBuf(state.RK), dhOut1);  const newDH = await generateDHPair();  const dhOut2 = await dh(newDH.priv, state.DHr);  const [RK2, CKs] = await kdfRK(RK1, dhOut2);  return {    ...state,    DHs_pub: newDH.pub, DHs_priv: newDH.priv,    RK: bufToBase64(RK2),    CKs: bufToBase64(CKs),    CKr: bufToBase64(CKr),  };}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0432\u0430 DH-\u0448\u0430\u0433\u0430 \u043f\u043e\u0434\u0440\u044f\u0434, \u043d\u0435 \u043e\u0434\u0438\u043d. \u042d\u0442\u043e \u0434\u0435\u0442\u0430\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043d\u0435 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u043d\u044f\u043b \u043f\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.<\/p>\n<ol>\n<li>\n<p><strong>\u041f\u0435\u0440\u0432\u044b\u0439 ECDH:<\/strong> \u043d\u0430\u0448 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 (<code>DHs_priv<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438) \u0441 \u043d\u043e\u0432\u044b\u043c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430 (<code>header_dh<\/code>). \u042d\u0442\u043e\u0442 ECDH \u0434\u0430\u0451\u0442 <code>RK1<\/code> \u0438 <code>CKr<\/code> \u2014 receiving chain \u0432 \u043d\u043e\u0432\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u0412\u0442\u043e\u0440\u043e\u0439 ECDH:<\/strong> \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u0443\u044e DH-\u043f\u0430\u0440\u0443 (<code>newDH<\/code>) \u0438 \u0434\u0435\u043b\u0430\u0435\u043c ECDH \u0435\u0451 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u0441 \u0442\u0435\u043c \u0436\u0435 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430. \u042d\u0442\u043e \u0434\u0430\u0451\u0442 <code>RK2<\/code> (\u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043d\u043e\u0432\u044b\u0439 RK) \u0438 <code>CKs<\/code> \u2014 sending chain \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u0417\u0430\u0447\u0435\u043c \u0434\u0432\u0430 \u0448\u0430\u0433\u0430? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430 \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b <strong>\u0438<\/strong> \u0434\u0435\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e (\u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u0435\u043d CKr), <strong>\u0438<\/strong> \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c \u0441\u043e \u0441\u0432\u0435\u0436\u0438\u043c ratchet-\u043a\u043b\u044e\u0447\u043e\u043c (\u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u0435\u043d CKs \u0438\u0437 \u041d\u041e\u0412\u041e\u0419 DH-\u043f\u0430\u0440\u044b). \u041e\u0434\u0438\u043d \u0448\u0430\u0433 \u0434\u0430\u0451\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u2014 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0445 \u0434\u0432\u0430.<\/p>\n<p>\u0421\u0447\u0451\u0442\u0447\u0438\u043a\u0438 \u0441\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u043d\u043e\u043b\u044c (<code>Ns<\/code>, <code>Nr<\/code>). \u0414\u043b\u0438\u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 <code>PN<\/code> \u2014 \u044d\u0442\u043e \u043f\u043e\u0439\u0434\u0451\u0442 \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044c \u0437\u043d\u0430\u043b, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u044e\u0447\u0435\u0439 \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 8. \u0413\u0440\u0430\u0431\u043b\u0438<\/h3>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f 1: Web Crypto requires raw buffers, \u043d\u0435 views.<\/strong><\/p>\n<p><code>base64ToBuf<\/code> \u0443 \u043c\u0435\u043d\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>ArrayBuffer<\/code>, \u043d\u043e \u0435\u0441\u043b\u0438 \u0431\u044b \u043e\u043d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b <code>Uint8Array<\/code> (\u0438\u043b\u0438 view), crypto.subtle \u043d\u0430 iOS \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442, \u0430 \u043d\u0430 Android \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f. Symptom: &#171;InvalidAccessError: Key usage not allowed&#187; \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0443\u0441\u0442\u043e\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u041f\u043e\u043f\u0440\u0430\u0432\u0438\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u0432\u0441\u0451 \u043a <code>ArrayBuffer<\/code> \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435.<\/p>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f 2: state.CKr \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c null \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438.<\/strong><\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0410\u043b\u0438\u0441\u0430 \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u0442 \u0447\u0430\u0442, \u0443 \u043d\u0435\u0451 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b <code>DHr<\/code> \u0438 <code>CKs<\/code>, \u043d\u043e <code>CKr<\/code> = null. \u041a\u043e\u0433\u0434\u0430 \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 <strong>\u043d\u0435 \u043e\u0442 \u0410\u043b\u0438\u0441\u044b<\/strong>, \u0430 <strong>\u043f\u0435\u0440\u0432\u044b\u0439 ratchet-step \u0434\u0435\u043b\u0430\u0435\u0442 \u0411\u043e\u0431<\/strong> \u2014 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0410\u043b\u0438\u0441\u044b \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c DH-\u0448\u0430\u0433, \u0438 <code>CKr<\/code> \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0432\u043f\u0435\u0440\u0432\u044b\u0435. \u042f \u0434\u043e\u043b\u0433\u043e \u043b\u043e\u0432\u0438\u043b \u0431\u0430\u0433 &#171;Cannot read property of null&#187; \u0432 \u043f\u0435\u0440\u0432\u043e\u043c DH-\u0448\u0430\u0433\u0435 \u0443 \u0438\u043d\u0438\u0446\u0438\u0430\u0442\u043e\u0440\u0430. \u0420\u0435\u0448\u0438\u043b\u043e\u0441\u044c \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u0432 <code>skipMessageKeys<\/code> (\u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435).<\/p>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f 3: state-race \u043d\u0430 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435.<\/strong><\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442 \u0434\u0432\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0440\u044f\u0434, <code>ratchetEncrypt<\/code> \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c\u0441\u044f \u0434\u0432\u0430\u0436\u0434\u044b \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e. \u041e\u0431\u0435 \u043a\u043e\u043f\u0438\u0438 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u044e\u0442 \u043e\u0434\u043d\u043e \u0438 \u0442\u043e \u0436\u0435 <code>state.CKs<\/code>, \u043e\u0431\u0435 \u0441\u0434\u0432\u0438\u043d\u0443\u0442 \u0441\u0447\u0451\u0442\u0447\u0438\u043a \u043d\u0430 1, \u043d\u043e \u0432 storage \u0437\u0430\u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043e\u0434\u043d\u043e \u0438\u0437 \u0434\u0432\u0443\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e \u0442\u0435\u043c \u0436\u0435 \u043a\u043b\u044e\u0447\u043e\u043c \u0447\u0442\u043e \u0438 \u0434\u0440\u0443\u0433\u043e\u0435 \u2014 \u043a\u0430\u0442\u0430\u0441\u0442\u0440\u043e\u0444\u0430 \u0434\u043b\u044f security \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. \u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u2014 \u043f\u0440\u043e\u0441\u0442\u0430\u044f mutex-\u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 chatId:<\/p>\n<pre><code class=\"typescript\">const ratchetMutex = new Map&lt;string, Promise&lt;void&gt;&gt;();async function withRatchetLock&lt;T&gt;(chatId: string, fn: () =&gt; Promise&lt;T&gt;): Promise&lt;T&gt; {  const prev = ratchetMutex.get(chatId) ?? Promise.resolve();  let release: () =&gt; void;  const next = new Promise&lt;void&gt;(r =&gt; { release = r; });  ratchetMutex.set(chatId, prev.then(() =&gt; next));  await prev;  try { return await fn(); }  finally { release!(); }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u0441\u0435 \u0432\u044b\u0437\u043e\u0432\u044b <code>ratchetEncrypt<\/code> \u0438 <code>ratchetDecrypt<\/code> \u043e\u0431\u0451\u0440\u043d\u0443\u0442\u044b \u0432 <code>withRatchetLock(chatId, () =&gt; ...)<\/code>. \u042d\u0442\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u0430\u0434 \u043e\u0434\u043d\u0438\u043c ratchet-state. \u0426\u0435\u043d\u0430 \u2014 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u043f\u0440\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435 (\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u043e\u0434\u043d\u0443 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0443).<\/p>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f 4: secure-store async \u043d\u0430 iOS.<\/strong><\/p>\n<p><code>expo-secure-store<\/code> \u043d\u0430 iOS \u0434\u0435\u043b\u0430\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0432\u044b\u0437\u043e\u0432 \u043a Keychain, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c 5-50\u043c\u0441 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 50 \u0447\u0430\u0442\u043e\u0432 \u0438 \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432\u0441\u0435 ratchet-state \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u2014 iOS Keychain \u0432\u044b\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0430\u0435\u0442 \u043d\u0430 \u043f\u0430\u0440\u0443 \u0441\u0435\u043a\u0443\u043d\u0434. \u0420\u0435\u0448\u0435\u043d\u0438\u0435: \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c ratchet-state <strong>\u043b\u0435\u043d\u0438\u0432\u043e<\/strong>, \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u0447\u0430\u0442 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0438\u043b\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435.<\/p>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f 5: PKCS#8 \u043d\u0435 \u0434\u0430\u0451\u0442 raw public key \u043e\u0431\u0440\u0430\u0442\u043d\u043e.<\/strong><\/p>\n<p>\u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>importEncryptedPrivateKey<\/code> \u0435\u0441\u0442\u044c \u0447\u0435\u0441\u0442\u043d\u043e\u0435 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0435 \u0432 \u043a\u043e\u0434\u0435:<\/p>\n<pre><code class=\"typescript\">\/\/ \u0418\u0437 pkcs8 \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c raw public. \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0442\u043e \u0447\u0442\u043e \u0435\u0441\u0442\u044c.<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0438\u0437 \u0431\u044d\u043a\u0430\u043f\u0430, \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0437 pkcs8 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0447\u0435\u0440\u0435\u0437 crypto.subtle \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u043e raw \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447. Public key \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043b\u0438\u0431\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0431\u044d\u043a\u0430\u043f\u0435, \u043b\u0438\u0431\u043e \u043f\u0435\u0440\u0435\u0434\u0435\u0440\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u0423 \u043c\u0435\u043d\u044f \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0438 \u0431\u044d\u043a\u0430\u043f\u0435. \u041d\u0435 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e \u2014 \u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 9. \u0427\u0442\u043e \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0437\u0430 \u043a\u0430\u0434\u0440\u043e\u043c<\/h3>\n<p>\u0427\u0442\u043e\u0431\u044b \u0431\u044b\u0442\u044c \u0447\u0435\u0441\u0442\u043d\u044b\u043c, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044e \u0447\u0442\u043e \u0443 \u043c\u0435\u043d\u044f <strong>\u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e<\/strong> \u0438 \u0447\u0442\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0443 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u0433\u043e Signal:<\/p>\n<ul>\n<li>\n<p><strong>X3DH<\/strong> \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u0433\u043e key agreement. \u0423 \u043c\u0435\u043d\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 ECDH \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u044b\u043c\u0438 \u043a\u043b\u044e\u0447\u0430\u043c\u0438, \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0435 \u0432\u044b\u0448\u0435.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0435 prekeys (one-time prekeys)<\/strong>. \u0423 Signal \u0441\u0435\u0440\u0432\u0435\u0440 \u0445\u0440\u0430\u043d\u0438\u0442 \u043f\u0430\u0447\u043a\u0443 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f; \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a offline-\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0448\u0438\u0444\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043d\u0438\u0445 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0435\u0433\u043e \u0432\u044b\u0434\u0430\u0451\u0442. \u0423 \u043c\u0435\u043d\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u0442, \u0447\u0442\u043e \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0441\u043b\u0430\u0431\u043b\u044f\u0435\u0442 \u0437\u0430\u0449\u0438\u0442\u0443 offline-\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0430.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0434\u043f\u0438\u0441\u0438 \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439.<\/strong> \u0412 Signal identity keys \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 prekey bundle. \u0423 \u043c\u0435\u043d\u044f \u043f\u043e\u043a\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0440\u0430\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0435\u0437 \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439 \u2014 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0434\u0430\u0442\u044c \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0435\u043c\u0443 \u0444\u0430\u043b\u044c\u0448\u0438\u0432\u044b\u0435 \u043a\u043b\u044e\u0447\u0438 \u0438 \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 MITM. \u041c\u0438\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Safety Numbers (\u043e\u0431 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435), \u043d\u043e \u044d\u0442\u043e \u0443\u0436\u0435 offline-\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u043d\u0435 \u043a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0430\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>Sealed Sender<\/strong> \u0432 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0432\u0438\u0434\u0435 Signal. \u0423 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u043b\u043d\u044b\u0439 Signal Sealed Sender \u0441\u043e sender certificates \u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043d\u044b\u043c revocation. \u0422\u043e\u0436\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u042f \u043f\u043e\u043d\u0438\u043c\u0430\u044e, \u0447\u0442\u043e \u043c\u043e\u0433 \u0431\u044b \u044d\u0442\u043e \u0432\u0441\u0451 \u0434\u043e\u0434\u0435\u043b\u0430\u0442\u044c, \u0438 \u0432 \u043a\u0430\u043a\u043e\u043c-\u0442\u043e \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0434\u043e\u0434\u0435\u043b\u0430\u044e. \u041d\u043e \u0432 state \u043a\u0430\u043a \u0441\u0435\u0439\u0447\u0430\u0441 Double Ratchet \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0434\u0430\u0451\u0442 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 forward secrecy \u0438 post-compromise security \u043f\u0440\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u0438, \u0447\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u043c\u0435\u043d \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u044e\u0442 Safety Numbers.<\/p>\n<h3>\u0418\u0442\u043e\u0433\u0438<\/h3>\n<p>Double Ratchet \u2014 \u043e\u0434\u0438\u043d \u0438\u0437 \u0442\u0435\u0445 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u0442\u0440\u0430\u0448\u043d\u043e (\u0442\u0430\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0448\u0430\u0433\u043e\u0432), \u0430 \u0432 \u043a\u043e\u0434\u0435 \u0443\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 ~300 \u0441\u0442\u0440\u043e\u043a, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u2014 \u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 crypto.subtle. \u0413\u043b\u0430\u0432\u043d\u044b\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0431\u044b\u043b\u0438 \u043d\u0435 \u0432 \u0441\u0430\u043c\u043e\u043c \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0435, \u0430 \u0432 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438: WebCrypto-quirks, race conditions \u043f\u0440\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435, lazy-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 edge cases \u0442\u0438\u043f\u0430 initial state \u0443 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0435 \u0434\u0435\u043b\u0430\u0442\u044c E2E \u0432 \u0441\u0432\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u2014 \u043c\u043e\u0439 \u0441\u043e\u0432\u0435\u0442: \u043d\u0435 \u0432\u044b\u0434\u0443\u043c\u044b\u0432\u0430\u0439\u0442\u0435 \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0439\u0442\u0435 Double Ratchet \u043f\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438. \u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f Signal <a href=\"https:\/\/signal.org\/docs\/specifications\/doubleratchet\/\" rel=\"noopener noreferrer nofollow\">\u043a\u043e\u0440\u043e\u0442\u043a\u0430\u044f \u0438 \u043f\u043e\u043d\u044f\u0442\u043d\u0430\u044f<\/a>, \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0437\u0430 \u0447\u0430\u0441. \u0411\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0440\u0435\u0448\u0430\u044e\u0442\u0441\u044f \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u043d\u043e\u043d\u0443, \u0430 \u043d\u0435 &#171;\u0438\u043d\u0442\u0443\u0438\u0442\u0438\u0432\u043d\u044b\u043c\u0438 \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f\u043c\u0438&#187;.<\/p>\n<p>\u0418 \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u0434\u0443\u043c\u0430\u0439\u0442\u0435 \u043f\u0440\u043e X3DH \u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0435\u0439. \u0421\u0430\u043c ratchet \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0443, \u043d\u043e \u0431\u0435\u0437 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 identity keys (Safety Numbers \u0438\u043b\u0438 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442) \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f MITM-\u0432\u0435\u043a\u0442\u043e\u0440 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0430. \u042d\u0442\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u0443\u0441\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0441\u0434\u0435\u043b\u0430\u044e \u043f\u0440\u0435\u0434\u043c\u0435\u0442\u043e\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<hr\/>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b <a href=\"#\" rel=\"noopener noreferrer nofollow\">\u0442\u0440\u0451\u0445\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043a\u044d\u0448 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439<\/a> \u2014 \u043e\u043d\u0430 \u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0439 8 \u0442\u044b\u0441\u044f\u0447\u0430\u043c \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439, \u0438 \u044d\u0442\u043e \u043c\u0435\u043d\u044f \u043e\u0447\u0435\u043d\u044c \u043c\u043e\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u043f\u043e \u043a\u043e\u0434\u0443, \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 \u0438\u043b\u0438 \u043f\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u2014 \u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b, \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u043e\u0439\u0434\u0451\u0442 \u0441\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435. \u0418 \u0435\u0441\u043b\u0438 \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u0431\u0430\u0433 \u2014 \u043f\u0438\u0448\u0438\u0442\u0435 \u0442\u043e\u0436\u0435, \u044f \u0435\u0433\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044e \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044e \u0432 &#171;\u0433\u0440\u0430\u0431\u043b\u0438&#187; \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c \u0430\u0432\u0442\u043e\u0440\u0430 \u043d\u0430\u0445\u043e\u0434\u043a\u0438.<\/p>\n<\/div>\n<p>\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\/1033830\/\">https:\/\/habr.com\/ru\/articles\/1033830\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0423\u0440\u043e\u0432\u0435\u043d\u044c: senior \u00b7 \u043d\u0443\u0436\u043d\u043e \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 (AES, ECDH, KDF) \u0421\u0442\u0435\u043a: React Native, Expo SDK 54, WebCrypto API, expo-secure-store, TypeScript \u0427\u0442\u043e \u0432\u043d\u0443\u0442\u0440\u0438: \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 Signal Double Ratchet, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 ~300 \u0441\u0442\u0440\u043e\u043a, \u0433\u0440\u0430\u0431\u043b\u0438, \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0438 \u043f\u0440\u043e \u043e\u0442\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u043e\u0442 \u043a\u0430\u043d\u043e\u043d\u0430\u0417\u0430\u0447\u0435\u043c \u043c\u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u0441\u044f Double Ratchet\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u043e \u0442\u0440\u0451\u0445\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u043a\u044d\u0448 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u044f \u0443\u0436\u0435 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u044e \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440 ONEMIX \u043d\u0430 React Native. \u0411\u0430\u0437\u043e\u0432\u043e\u0435 E2E \u0443 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0435: ECDH P-256 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u0435, AES-GCM \u0434\u043b\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0438\u043c \u0441\u0435\u043a\u0440\u0435\u0442\u043e\u043c. \u042d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u043e\u0434\u043d\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443: \u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442 \u043e\u0434\u0438\u043d \u043d\u0430 \u0432\u0441\u044e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0443. \u0415\u0441\u043b\u0438 \u0443 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u0441\u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0438\u0440\u0443\u044e\u0442 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u2014 \u0432\u0441\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0437\u0430 \u0432\u0441\u0451 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442.\u042d\u0442\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435\u043c Perfect Forward Secrecy (PFS). \u0418 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0432 \u0440\u0443\u043a\u0438 \u043f\u043e\u043f\u0430\u0434\u0451\u0442 \u0442\u0432\u043e\u0439 \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u0447\u0435\u0440\u0435\u0437 \u0433\u043e\u0434, \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0443 \u0438\u0437 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0433\u043e\u0434\u0430. WhatsApp, Signal, \u0438 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u0447\u0430\u0441\u0442\u0438 Telegram \u0434\u0430\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0434\u0440\u0443\u0433\u0443\u044e \u0441\u0445\u0435\u043c\u0443 \u2014 Double Ratchet \u2014 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043a\u043b\u044e\u0447\u0438 \u043f\u0435\u0440\u0435\u0438\u0437\u0431\u0440\u0435\u0442\u0430\u0435\u0442 \u0437\u0430\u043d\u043e\u0432\u043e \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438. \u0422\u0430\u043a \u0434\u0435\u043b\u0430\u044e\u0442 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043b\u044e\u0431\u043e\u0439 \u043a\u043b\u044e\u0447 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u0438\u043d \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0438 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0430\u0446\u0438\u044f \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0434\u0430\u0432\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0438 \u043a \u043f\u0440\u043e\u0448\u043b\u043e\u043c\u0443, \u043d\u0438 \u043a \u0431\u0443\u0434\u0443\u0449\u0435\u043c\u0443.\u042f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b Double Ratchet \u0441 \u043d\u0443\u043b\u044f \u0434\u043b\u044f ONEMIX. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443:\u041a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u0438\u0434\u0435\u0438 (\u0431\u0435\u0437 \u043c\u0430\u0442\u0430\u043d\u0430).\u041c\u043e\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 ~300 \u0441\u0442\u0440\u043e\u043a TypeScript \u043f\u043e\u0432\u0435\u0440\u0445 WebCrypto API.\u0413\u0434\u0435 \u044f \u043e\u0442\u0441\u0442\u0443\u043f\u0438\u043b \u043e\u0442 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e Signal Protocol \u0438 \u043f\u043e\u0447\u0435\u043c\u0443.\u0413\u0440\u0430\u0431\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u0441\u043e\u0431\u0440\u0430\u043b \u043f\u043e \u0434\u043e\u0440\u043e\u0433\u0435.\u0421\u0440\u0430\u0437\u0443 \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0430 \u043f\u0440\u043e &#171;production-grade&#187;. \u042f \u0434\u0435\u043b\u0430\u044e \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440 \u043e\u0434\u0438\u043d, \u043c\u043e\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0448\u043b\u0430 \u043c\u043e\u0438 \u0442\u0435\u0441\u0442\u044b, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0430\u0443\u0434\u0438\u0442 NCC Group \u0438 \u043d\u0435 Trail of Bits. \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0435\u0437\u0443\u043f\u0440\u0435\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u2014 \u0431\u0435\u0440\u0438\u0442\u0435 libsignal-protocol-typescript \u0438\u043b\u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0438. \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u2014 \u043f\u0440\u043e \u0442\u043e, \u043a\u0430\u043a \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0432\u043d\u0443\u0442\u0440\u0438 \u0438 \u043a\u0430\u043a \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0440\u0443\u043a\u0430\u043c\u0438. \u041f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e, \u0447\u0435\u043c \u0442\u044b \u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0448\u044c\u0441\u044f. \u0423\u0447\u0438\u0442\u044c\u0441\u044f \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e, \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0441\u0430\u043c\u043e\u043c\u0443, \u0440\u0430\u0437\u0431\u0438\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0438 \u0441\u043e\u0431\u0440\u0430\u0432 \u0441\u043d\u043e\u0432\u0430.\u0427\u0430\u0441\u0442\u044c 1. \u0418\u0434\u0435\u044f Double Ratchet \u0437\u0430 5 \u043c\u0438\u043d\u0443\u0442\u0423 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0434\u0432\u0430 &#171;\u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a\u0430&#187; (\u043e\u0442\u0441\u044e\u0434\u0430 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435). \u041a\u0430\u0436\u0434\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a \u2014 \u044d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0432\u0438\u0433\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043f\u0435\u0440\u0451\u0434: \u043f\u043e\u0441\u043b\u0435 \u0449\u0435\u043b\u0447\u043a\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0437\u043d\u0430\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0435\u0433\u043e\u0434\u043d\u044f, \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0432\u0447\u0435\u0440\u0430\u0448\u043d\u0435\u0435.\u0421\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a (Symmetric Ratchet). \u041d\u0430 \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0431\u0435\u0440\u0451\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u0439 &#171;chain key&#187; (CK), \u0438 \u0438\u0437 \u043d\u0435\u0433\u043e KDF \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0434\u0432\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f: \u043d\u043e\u0432\u044b\u0439 chain key \u0438 message key (MK). MK \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437 \u0434\u043b\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438 \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f. CK \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u2014 \u0441\u0442\u0430\u0440\u044b\u0439 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f. \u0415\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442 CK \u0441\u0435\u0439\u0447\u0430\u0441, \u043e\u043d \u0441\u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 MK \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043d\u043e \u043d\u0435 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e KDF \u2014 \u043e\u0434\u043d\u043e\u0441\u0442\u043e\u0440\u043e\u043d\u043d\u044f\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f.CK_0 \u2192 KDF \u2192 (CK_1, MK_0)    # \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 0 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e MK_0CK_1 \u2192 KDF \u2192 (CK_2, MK_1)    # \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 1 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e MK_1CK_2 \u2192 KDF \u2192 (CK_3, MK_2)    # \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 2 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e MK_2\u042d\u0442\u043e \u0434\u0430\u0451\u0442 forward secrecy \u0432 \u043e\u0434\u043d\u0443 \u0441\u0442\u043e\u0440\u043e\u043d\u0443: \u0437\u0430\u0445\u0432\u0430\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0435 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0448\u043b\u043e\u0435. \u041d\u043e \u043d\u0435 \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u0431\u0443\u0434\u0443\u0449\u0435\u0439 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0435\u0442\u0430\u0446\u0438\u0438 \u0432 \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u0442\u043e\u0440\u043e\u043d\u0443 \u2014 \u0435\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0437\u043d\u0430\u0435\u0442 CK_2, \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c CK_3, CK_4 \u0438 \u0432\u0441\u0451 \u0447\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435.DH-\u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a (DH Ratchet). \u0420\u0435\u0448\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043a\u043e\u0433\u0434\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u043e\u043b\u044f\u043c\u0438 (\u0410\u043b\u0438\u0441\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0430, \u0411\u043e\u0431 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442), \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u0430\u044f \u043f\u0430\u0440\u0430 DH-\u043a\u043b\u044e\u0447\u0435\u0439. \u0418\u0437 ECDH \u0441 \u043d\u043e\u0432\u044b\u043c\u0438 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442, \u0438 \u0438\u0437 \u043d\u0435\u0433\u043e HKDF \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043d\u043e\u0432\u044b\u0439 root key (RK) \u0438 \u043d\u043e\u0432\u044b\u0439 chain key \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438. \u042d\u0442\u043e\u0442 \u0448\u0430\u0433 &#171;\u043f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442&#187; \u0441\u0438\u043c\u043c\u0435\u0442\u0440\u0438\u0447\u043d\u044b\u0439 \u0445\u0440\u0430\u043f\u043e\u0432\u0438\u043a \u0441 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0439 \u043e\u0442 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0439 \u0432\u0435\u043b\u0438\u0447\u0438\u043d\u043e\u0439. \u042d\u0442\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f post-compromise security \u0438\u043b\u0438 break-in recovery: \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0437\u043b\u043e\u0443\u043c\u044b\u0448\u043b\u0435\u043d\u043d\u0438\u043a \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u043b \u043f\u043e\u043b\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u043f\u043e\u0441\u043b\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e DH-\u0448\u0430\u0433\u0430 \u043e\u043d \u0441\u043d\u043e\u0432\u0430 \u0432 \u043d\u0435\u0432\u0435\u0434\u0435\u043d\u0438\u0438.\u0412\u043c\u0435\u0441\u0442\u0435 \u043e\u043d\u0438 \u0434\u0430\u044e\u0442 \u0442\u043e \u0441\u0430\u043c\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e Signal: \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043e \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0438 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445, \u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u043f\u043e\u0441\u043b\u0435 DH-\u0448\u0430\u0433\u0430.\u0418 \u043e\u0434\u0438\u043d \u0442\u043e\u043d\u043a\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u043d\u0435 \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443. \u0415\u0441\u043b\u0438 \u0410\u043b\u0438\u0441\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0430 5 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u0430 \u0443 \u0411\u043e\u0431\u0430 \u043f\u0440\u0438\u0448\u043b\u0438 #1, #3, #5 (\u0430 #2 \u0438 #4 \u0437\u0430\u0441\u0442\u0440\u044f\u043b\u0438 \u0432 Push-\u043d\u043e\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\u0445), \u0411\u043e\u0431 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043c\u0435\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c #3 \u043d\u0435 \u0437\u043d\u0430\u044f #2. \u042d\u0442\u043e \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 skipped message keys: \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 #3 \u0411\u043e\u0431 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442 MK \u0434\u043b\u044f #2 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0435\u0433\u043e \u0432 MKSKIPPED. \u041a\u043e\u0433\u0434\u0430 #2 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442, \u0411\u043e\u0431 \u0434\u043e\u0441\u0442\u0430\u0451\u0442 MK \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0430\u0435\u0442. \u0420\u0430\u0437\u043c\u0435\u0440 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d (MAX_SKIP) \u2014 \u0438\u043d\u0430\u0447\u0435 \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0438\u0439 \u043c\u043e\u0433 \u0431\u044b \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0441 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u044b \u043a\u043b\u044e\u0447\u0435\u0439.\u042d\u0442\u043e\u0433\u043e \u0445\u0432\u0430\u0442\u0438\u0442 \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u043a\u043e\u0434.\u0427\u0430\u0441\u0442\u044c 2. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Double Ratchet \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0447\u0430\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0443 \u043c\u0435\u043d\u044f \u0442\u0430\u043a:export interface RatchetState {  \/\/ DH \u043f\u0430\u0440\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f  DHs_pub:  string;   \/\/ base64 raw  DHs_priv: string;   \/\/ base64 pkcs8  \/\/ DH \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0441\u043e\u0431\u0435\u0441\u0435\u0434\u043d\u0438\u043a\u0430  DHr:      string | null;  \/\/ \u041a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043a\u043b\u044e\u0447  RK:       string;   \/\/ base64, 32 \u0431\u0430\u0439\u0442\u0430  \/\/ \u0426\u0435\u043f\u043e\u0447\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438\/\u043f\u0440\u0438\u0451\u043c\u0430  CKs:      string | null;  \/\/ sending chain key  CKr:      string | null;  \/\/ receiving chain key  \/\/ \u0421\u0447\u0451\u0442\u0447\u0438\u043a\u0438  Ns:       number;   \/\/ sent messages counter  Nr:       number;   \/\/ received messages counter  PN:       number;   \/\/ prev sending chain length  \/\/ Skipped message keys (\u0434\u043b\u044f out-of-order)  MKSKIPPED: Record&lt;string, string&gt;; \/\/ &#171;pubkey:N&#187; \u2192 base64 key}\u0418\u043c\u0435\u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u0437\u044f\u0442\u044b \u043f\u0440\u044f\u043c\u043e \u0438\u0437 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 Signal Double Ratchet. \u042d\u0442\u043e \u043d\u0435 \u0438\u0437 \u044d\u0441\u0442\u0435\u0442\u0438\u043a\u0438 \u2014 \u044d\u0442\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0447\u0442\u0435\u043d\u0438\u0435 \u0441\u043f\u0435\u043a\u0438 \u0440\u044f\u0434\u043e\u043c \u0441 \u043a\u043e\u0434\u043e\u043c, \u0438 \u043b\u044e\u0431\u043e\u0439 \u043a\u0442\u043e \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0443\u0437\u043d\u0430\u0451\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0430\u0437\u0443.\u0421\u043e\u0445\u0440\u0430\u043d\u044f\u044e \u044d\u0442\u043e \u0432\u0441\u0451 \u0432 expo-secure-store, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 iOS Keychain \u0438 Android Keystore. \u042d\u0442\u043e \u043d\u0435 \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u0430\u044f \u043a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0437\u0430\u0449\u0438\u0442\u0430 (Keychain \u043d\u0435 \u0437\u0430\u0449\u0438\u0449\u0430\u0435\u0442 \u043e\u0442 \u0440\u0443\u0442\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430), \u043d\u043e \u044d\u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u0447\u0435\u043c AsyncStorage, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043b\u0435\u0436\u0438\u0442 plain \u0432 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\u041e\u0434\u0438\u043d ratchet-state \u043d\u0430 \u0447\u0430\u0442: onemix_ratchet_${chatId}. \u0415\u0441\u043b\u0438 \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f 50 \u0447\u0430\u0442\u043e\u0432 \u2014 50 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 ratchet-state.\u0427\u0430\u0441\u0442\u044c 3. \u041a\u0440\u0438\u043f\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b\u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b \u2014 \u0447\u0435\u0440\u0435\u0437 crypto.subtle (WebCrypto API). \u0412 Expo SDK 54 \u043e\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 react-native-quick-crypto \u0438\u043b\u0438 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 polyfill&#8217;\u044b. \u042d\u0442\u043e \u043d\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u043d\u0435 \u043d\u0430 JS, \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0434\u0430\u0436\u0435 \u043d\u0430 \u0431\u044e\u0434\u0436\u0435\u0442\u043d\u044b\u0445 Android.\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f ECDH-\u043f\u0430\u0440\u044b:async function generateDHPair(): Promise&lt;{ pub: string; priv: string }&gt; {  const kp = await crypto.subtle.generateKey(    { name: &#171;ECDH&#187;, namedCurve: &#171;P-256&#187; }, true, [&#171;deriveKey&#187;, &#171;deriveBits&#187;]  );  const pub  = await crypto.subtle.exportKey(&#171;raw&#187;,   kp.publicKey);  const priv = await crypto.subtle.exportKey(&#171;pkcs8&#187;, kp.privateKey);  return { pub: bufToBase64(pub), priv: bufToBase64(priv) };}\u0421\u0440\u0430\u0437\u0443 \u0432\u0430\u0436\u043d\u0430\u044f \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0430. \u041a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 Signal Protocol \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 Curve25519 (X25519 \u0434\u043b\u044f ECDH, Ed25519 \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439). Curve25519 \u0438\u043c\u0435\u0435\u0442 \u0440\u044f\u0434 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432 \u043f\u0435\u0440\u0435\u0434 P-256: \u043f\u0440\u043e\u0449\u0435 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 side-channel \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0437\u0430\u0432\u0435\u0434\u043e\u043c\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b (\u0434\u043b\u044f P-256 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u0437\u044f\u0442\u044b \u0438\u0437 NIST \u0438 \u0435\u0441\u0442\u044c \u0442\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u043e\u043c\u043d\u0435\u043d\u0438\u044f \u0432 \u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0441\u0442\u0438), \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043d\u0430 \u0431\u044e\u0434\u0436\u0435\u0442\u043d\u043e\u043c \u0436\u0435\u043b\u0435\u0437\u0435.\u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e P-256, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e WebCrypto API \u0432 RN \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 Curve25519 \u043d\u0430\u0442\u0438\u0432\u043d\u043e. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c X25519 \u0432 \u0447\u0438\u0441\u0442\u043e\u043c JS \u043c\u043e\u0436\u043d\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0435\u0440\u0435\u0437 @noble\/curves), \u043d\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e crypto.subtle \u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u0443\u0434\u0438\u0442\u0430 \u0441\u0430\u043c\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438. \u042f \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043b \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439 P-256 \u0446\u0435\u043d\u043e\u0439 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u043e\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u043d\u0435 Signal Protocol, \u0430 Double Ratchet \u043d\u0430 P-256. \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 threat models \u044d\u0442\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e. \u0415\u0441\u043b\u0438 \u0432\u0430\u0448\u0430 threat model \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 NSA-level \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u0438\u043a\u0430 \u0438 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e \u043f\u043e\u0434\u0441\u0430\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 NIST \u2014 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u0435 \u043d\u0430 Curve25519 \u0447\u0435\u0440\u0435\u0437 @noble\/curves \u0438\u043b\u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0431\u0438\u043d\u0434\u0438\u043d\u0433\u0438.ECDH:async function dh(privB64: string, pubB64: string): Promise&lt;ArrayBuffer&gt; {  const privKey = await crypto.subtle.importKey(    &#171;pkcs8&#187;, base64ToBuf(privB64),    { name: &#171;ECDH&#187;, namedCurve: &#171;P-256&#187; }, false, [&#171;deriveBits&#187;]  );  const pubKey = await crypto.subtle.importKey(    &#171;raw&#187;, base64ToBuf(pubB64),    { name: &#171;ECDH&#187;, namedCurve: &#171;P-256&#187; }, false, []  );  return crypto.subtle.deriveBits({ name: &#171;ECDH&#187;, public: pubKey }, privKey, 256);}HKDF \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u043d\u044b\u0445 KDF \u2014 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0438 \u0446\u0435\u043f\u043e\u0447\u043d\u043e\u0433\u043e:async function hkdf(input: ArrayBuffer, salt: string, info: string, length = 32): Promise&lt;ArrayBuffer&gt; {  const key  = await importHKDFKey(input);  return crypto.subtle.deriveBits(    { name: &#171;HKDF&#187;, hash: &#171;SHA-256&#187;, salt: enc.encode(salt), info: enc.encode(info) },    key, length * 8  );}\/** KDF \u0434\u043b\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0430: \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 [\u043d\u043e\u0432\u044b\u0439 RK, chain key] *\/async function kdfRK(rk: ArrayBuffer, dhOut: ArrayBuffer): Promise&lt;[ArrayBuffer, ArrayBuffer]&gt; {  const combined = await hkdf(dhOut, dec.decode(rk), &#171;onemix-ratchet-rk&#187;, 64);  return [combined.slice(0, 32), combined.slice(32)];}\/** KDF \u0434\u043b\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0438: \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 [\u043d\u043e\u0432\u044b\u0439 CK, message key] *\/async function kdfCK(ck: ArrayBuffer): Promise&lt;[ArrayBuffer, ArrayBuffer]&gt; {  const [ckBytes, mkBytes] = await Promise.all([    hkdf(ck, &#171;onemix-chain-key&#187;, &#171;onemix-ck&#187;, 32),    hkdf(ck, &#171;onemix-msg-key&#187;,   &#171;onemix-mk&#187;, 32),  ]);  return [ckBytes, mkBytes];}\u0422\u0443\u0442 \u0435\u0441\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u043d\u0430 \u0442\u043e\u043d\u043a\u043e\u0441\u0442\u044c, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430\u0434\u043e \u0447\u0435\u0441\u0442\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c. \u0412 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u043c Signal Double Ratchet kdfCK \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 HMAC \u0441 \u0434\u0432\u0443\u043c\u044f \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0430\u043c\u0438 (0x01 \u0438 0x02 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 input), \u0430 \u043d\u0435 \u0434\u0432\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 HKDF-\u0432\u044b\u0437\u043e\u0432\u0430. \u042d\u0442\u043e \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u0430\u044f \u043f\u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f, \u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u0430\u044f. \u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0434\u0432\u0435 HKDF-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0443 crypto.subtle \u043d\u0430\u0442\u0438\u0432\u043d\u043e \u0435\u0441\u0442\u044c HKDF, \u043d\u043e \u043d\u0435\u0442 \u043f\u0440\u044f\u043c\u043e\u0433\u043e HMAC-based ratchet primitive \u2014 \u0430 \u0437\u0430\u0432\u043e\u0434\u0438\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u043d\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e HMAC \u043f\u043e\u0432\u0435\u0440\u0445 HKDF \u043c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c. \u0421\u0435\u043c\u0430\u043d\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0442\u043e\u0442 \u0436\u0435: \u0434\u0432\u0430 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445 32-\u0431\u0430\u0439\u0442\u043d\u044b\u0445 \u043a\u043b\u044e\u0447\u0430 \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0445\u043e\u0434\u0430.\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e, kdfRK \u0432 \u043a\u0430\u043d\u043e\u043d\u0435 \u2014 \u044d\u0442\u043e HKDF \u0441 \u0434\u0432\u0443\u043c\u044f \u0432\u044b\u0445\u043e\u0434\u0430\u043c\u0438 (RK || CK) \u0434\u043b\u0438\u043d\u044b 64 \u0431\u0430\u0439\u0442\u0430, \u0440\u0430\u0437\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043f\u043e\u043b\u0430\u043c. \u042d\u0442\u043e \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0432 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438.\u0427\u0430\u0441\u0442\u044c 4. \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u041a\u043e\u0433\u0434\u0430 \u0410\u043b\u0438\u0441\u0430 \u0438 \u0411\u043e\u0431 \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u043a\u0443, \u0443 \u043d\u0430\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0431\u0449\u0438\u0439 \u0441\u0435\u043a\u0440\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u0435\u0440\u0432\u0443\u044e \u0446\u0435\u043f\u043e\u0447\u043a\u0443. \u0412 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u043c Signal \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 X3DH \u2014 Triple Diffie-Hellman, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u0443\u0435\u0442 identity keys, signed prekeys \u0438 one-time prekeys \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f shared secret \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 replay.\u042f \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u043f\u043e\u043b\u043d\u044b\u0439 X3DH. \u0423 \u043c\u0435\u043d\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043e\u0431\u043c\u0435\u043d: \u043e\u0434\u0438\u043d ECDH \u043c\u0435\u0436\u0434\u0443 \u0434\u043e\u043b\u0433\u043e\u0441\u0440\u043e\u0447\u043d\u044b\u043c\u0438 \u043a\u043b\u044e\u0447\u0430\u043c\u0438 \u043e\u0431\u0435\u0438\u0445 \u0441\u0442\u043e\u0440\u043e\u043d. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0447\u0442\u043e \u043c\u043e\u0439 \u043f\u0435\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 shared secret \u0443\u044f\u0437\u0432\u0438\u043c \u043a replay (\u0435\u0441\u043b\u0438 \u043a\u0442\u043e-\u0442\u043e \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u043b \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0410\u043b\u0438\u0441\u044b \u0438 \u0448\u0435\u0441\u0442\u044c \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u0441\u043f\u0443\u0441\u0442\u044f&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-479334","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/479334","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=479334"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/479334\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=479334"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=479334"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=479334"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}