Chepuhagram/srv/site/about-secutity/index.html

720 lines
28 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Архитектура Безопасности и Шифрования — Чепухаграм</title>
<meta name="description" content="Подробный разбор сквозного шифрования (E2EE) мессенджера Чепухаграм. Узнайте об использовании протоколов X25519, AES-256-GCM, PBKDF2 и поблочной защите медиафайлов.">
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700&family=Inter:wght@300;400;500;600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--bg-color: #0b071a;
--bg-card: #14102d;
--accent-color: #7c4dff;
--accent-light: #9e75ff;
--accent-glow: rgba(124, 77, 255, 0.3);
--text-primary: #ffffff;
--text-secondary: #94a3b8;
--glass-bg: rgba(255, 255, 255, 0.03);
--glass-border: rgba(255, 255, 255, 0.08);
--code-bg: #110c26;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
background-color: var(--bg-color);
color: var(--text-primary);
overflow-x: hidden;
line-height: 1.75;
}
h1, h2, h3, h4, .logo {
font-family: 'Outfit', sans-serif;
}
/* Custom Scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-color);
}
::-webkit-scrollbar-thumb {
background: var(--glass-border);
border-radius: 4px;
transition: background 0.3s;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent-color);
}
.container {
width: 100%;
max-width: 1000px;
margin: 0 auto;
padding: 0 24px;
}
/* Header Navigation */
header {
background: rgba(11, 7, 26, 0.8);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--glass-border);
padding: 16px 0;
position: sticky;
top: 0;
z-index: 100;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 22px;
font-weight: 700;
color: var(--text-primary);
display: flex;
align-items: center;
gap: 10px;
text-decoration: none;
}
.logo-dot {
width: 8px;
height: 8px;
background-color: var(--accent-color);
border-radius: 50%;
box-shadow: 0 0 10px var(--accent-color);
}
.btn-back {
color: var(--text-secondary);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: color 0.3s;
display: flex;
align-items: center;
gap: 6px;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
padding: 8px 16px;
border-radius: 20px;
}
.btn-back:hover {
color: var(--text-primary);
border-color: rgba(255, 255, 255, 0.2);
background: rgba(255, 255, 255, 0.06);
}
/* Hero Section */
.hero {
padding: 80px 0 40px 0;
background: radial-gradient(circle at 50% -20%, rgba(124, 77, 255, 0.12) 0%, transparent 60%);
}
.hero h1 {
font-size: 46px;
font-weight: 700;
margin-bottom: 16px;
line-height: 1.2;
background: linear-gradient(135deg, #ffffff 40%, #d1c4e9 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hero-meta {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 40px;
}
/* Article Content */
.content-section {
padding-bottom: 80px;
}
.intro-text {
font-size: 18px;
font-weight: 300;
color: #e2e8f0;
margin-bottom: 40px;
line-height: 1.8;
}
h2 {
font-size: 28px;
font-weight: 700;
margin: 54px 0 24px 0;
border-left: 4px solid var(--accent-color);
padding-left: 16px;
color: #f8fafc;
}
h3 {
font-size: 20px;
font-weight: 600;
margin: 32px 0 16px 0;
color: #f1f5f9;
}
p {
margin-bottom: 24px;
color: #cbd5e1;
}
ul, ol {
margin-bottom: 28px;
padding-left: 24px;
color: #cbd5e1;
}
li {
margin-bottom: 10px;
}
/* Tech Spec Grid */
.spec-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
margin: 40px 0;
}
.spec-card {
background: var(--bg-card);
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: 28px 24px;
text-align: center;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
transition: transform 0.3s;
}
.spec-card:hover {
transform: translateY(-4px);
}
.spec-card .icon {
font-size: 32px;
margin-bottom: 16px;
display: inline-block;
}
.spec-card h3 {
font-size: 16px;
color: var(--text-primary);
margin: 0 0 8px 0;
font-weight: 600;
}
.spec-card p {
font-size: 13px;
color: var(--text-secondary);
margin-bottom: 0;
line-height: 1.5;
}
/* Cryptographic Exchange Diagram (CSS representation) */
.dh-diagram {
display: flex;
justify-content: space-between;
align-items: center;
background: var(--bg-card);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 36px 30px;
margin: 40px 0;
gap: 20px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
}
.dh-entity {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
width: 32%;
}
.dh-avatar {
width: 54px;
height: 54px;
background: linear-gradient(135deg, var(--accent-color), #b388ff);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
color: white;
font-size: 15px;
box-shadow: 0 4px 15px var(--accent-glow);
}
.dh-avatar.bob {
background: linear-gradient(135deg, #00b0ff, #00e5ff);
box-shadow: 0 4px 15px rgba(0, 176, 255, 0.3);
}
.dh-key {
padding: 8px 12px;
border-radius: 8px;
font-size: 11px;
text-align: center;
width: 100%;
font-weight: 500;
font-family: 'Fira Code', monospace;
}
.dh-key.private {
background: rgba(239, 83, 80, 0.12);
border: 1px solid rgba(239, 83, 80, 0.25);
color: #ef5350;
}
.dh-key.public {
background: rgba(76, 217, 100, 0.12);
border: 1px solid rgba(76, 217, 100, 0.25);
color: #4cd964;
}
.dh-key.shared {
background: rgba(124, 77, 255, 0.15);
border: 1px solid rgba(124, 77, 255, 0.3);
color: #b388ff;
font-size: 12px;
font-weight: 600;
}
.dh-channel {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
font-size: 11px;
color: var(--text-secondary);
}
.dh-arrow {
background: rgba(255, 255, 255, 0.04);
padding: 6px 12px;
border-radius: 20px;
border: 1px solid var(--glass-border);
width: 100%;
text-align: center;
font-weight: 500;
}
/* File Block Stream Encryption Diagram */
.block-stream-diagram {
display: flex;
flex-direction: column;
align-items: center;
background: var(--bg-card);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 36px 30px;
margin: 40px 0;
gap: 20px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
}
.stream-file {
background: linear-gradient(135deg, var(--accent-color) 0%, #5e35b1 100%);
padding: 12px 36px;
border-radius: 12px;
font-weight: 600;
box-shadow: 0 4px 15px var(--accent-glow);
font-size: 14px;
}
.stream-split {
font-size: 12px;
color: var(--text-secondary);
font-style: italic;
}
.stream-blocks {
display: flex;
gap: 16px;
width: 100%;
justify-content: center;
flex-wrap: wrap;
}
.stream-block {
background: rgba(255, 255, 255, 0.02);
border: 1px solid var(--glass-border);
border-radius: 14px;
padding: 18px;
flex: 1;
min-width: 220px;
text-align: center;
}
.stream-block.tail {
border-style: dashed;
border-color: rgba(255, 255, 255, 0.2);
}
.block-title {
font-size: 13px;
font-weight: 600;
display: block;
margin-bottom: 8px;
color: #fff;
}
.block-crypto {
font-size: 11px;
color: var(--accent-light);
margin-bottom: 10px;
font-weight: 500;
}
.block-result {
font-size: 11px;
color: var(--text-secondary);
background: rgba(0, 0, 0, 0.25);
padding: 8px 10px;
border-radius: 8px;
line-height: 1.4;
font-family: 'Fira Code', monospace;
}
/* Encryption Steps Visualizer */
.steps {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 40px;
margin: 40px 0;
position: relative;
}
.step-item {
display: flex;
gap: 24px;
margin-bottom: 32px;
position: relative;
}
.step-item:last-child {
margin-bottom: 0;
}
.step-item:not(:last-child)::after {
content: '';
position: absolute;
top: 36px;
left: 18px;
width: 2px;
height: calc(100% - 4px);
background: var(--glass-border);
}
.step-num {
width: 38px;
height: 38px;
background: var(--accent-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 15px;
flex-shrink: 0;
box-shadow: 0 0 10px var(--accent-glow);
}
.step-content h3 {
font-size: 18px;
margin: 0 0 8px 0;
font-weight: 600;
}
.step-content p {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 0;
}
/* Code Block Container */
.code-container {
background: var(--code-bg);
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: 24px;
margin: 32px 0;
overflow-x: auto;
position: relative;
}
.code-container::before {
content: 'Dart / PointyCastle / Cryptography';
position: absolute;
top: 8px;
right: 16px;
font-size: 10px;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 1px;
}
code {
font-family: 'Fira Code', monospace;
font-size: 13px;
color: #e2e8f0;
}
/* Callout Box */
.callout {
background: rgba(124, 77, 255, 0.08);
border-left: 4px solid var(--accent-color);
padding: 20px 24px;
border-radius: 0 16px 16px 0;
margin: 32px 0;
}
.callout p {
margin-bottom: 0;
font-size: 14px;
color: #e2e8f0;
}
/* Footer */
footer {
border-top: 1px solid var(--glass-border);
padding: 45px 0;
text-align: center;
background: #06040e;
}
.footer-logo {
font-size: 18px;
font-weight: 700;
color: white;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
}
@media (max-width: 768px) {
.dh-diagram {
flex-direction: column;
gap: 30px;
padding: 30px 20px;
}
.dh-entity {
width: 100%;
}
.dh-channel {
width: 100%;
}
.block-stream-diagram {
padding: 30px 20px;
}
.stream-blocks {
flex-direction: column;
}
.hero h1 {
font-size: 34px;
}
}
</style>
</head>
<body>
<!-- Header Navigation -->
<header>
<div class="container header-content">
<a href="../index.html" class="logo" id="headerLogo">
<span class="logo-dot"></span>Чепухаграм
</a>
<a href="../index.html" class="btn-back" id="backLink">
На главную
</a>
</div>
</header>
<!-- Hero Header -->
<section class="hero">
<div class="container">
<h1 id="titleHeader">Безопасность и сквозное шифрование (E2EE)</h1>
<div class="hero-meta" id="metaDate">Обновлено: Июнь 2026 • Документация Чепухаграм</div>
<p class="intro-text" id="introDesc">В мессенджере Чепухаграм конфиденциальность переписки обеспечивается математическими законами. Никакие третьи лица, включая разработчиков и администраторов серверов, не могут получить доступ к содержимому ваших чатов.</p>
</div>
</section>
<!-- Main Content -->
<div class="container content-section">
<!-- Technical Specifications -->
<div class="spec-grid" id="specGrid">
<div class="spec-card">
<span class="icon">🔑</span>
<h3>X25519</h3>
<p>Протокол Диффи-Хеллмана для генерации общего ключа (ECDH)</p>
</div>
<div class="spec-card">
<span class="icon">⚙️</span>
<h3>AES-256-GCM</h3>
<p>Симметричное шифрование с проверкой целостности данных</p>
</div>
<div class="spec-card">
<span class="icon">🔒</span>
<h3>PBKDF2</h3>
<p>Криптографическая деривация ключей на базе мастер-пароля (600,000 ит.)</p>
</div>
</div>
<h2 id="e2eeHeader">Принцип сквозного шифрования (E2EE)</h2>
<p>Шифрование «end-to-end» означает, что шифрование информации происходит непосредственно на устройстве отправителя, а дешифрование — только на устройстве получателя. Серверная часть выполняет лишь функцию почтальона — пересылает зашифрованные пакеты байт, не имея ключей для их расшифровки.</p>
<!-- ECDH Exchange Visual Diagram -->
<h3>Схема согласования ключей (X25519)</h3>
<div class="dh-diagram">
<div class="dh-entity">
<div class="dh-avatar">Вы</div>
<div class="dh-key private">Приватный ключ A</div>
<div class="dh-key public">Публичный ключ A</div>
<div class="dh-key shared">Общий секрет (K)</div>
</div>
<div class="dh-channel">
<div class="dh-arrow">публичный ключ A →</div>
<div class="dh-arrow">← публичный ключ B</div>
<p style="margin: 8px 0 0 0; text-align: center; font-size: 11px;">(сервер пересылает только публичные ключи)</p>
</div>
<div class="dh-entity">
<div class="dh-avatar bob">Собеседник</div>
<div class="dh-key private">Приватный ключ B</div>
<div class="dh-key public">Публичный ключ B</div>
<div class="dh-key shared">Общий секрет (K)</div>
</div>
</div>
<div class="steps" id="stepsSection">
<div class="step-item">
<div class="step-num">1</div>
<div class="step-content">
<h3>Создание пары ключей</h3>
<p>При первом запуске приложения Чепухаграм генерирует на устройстве пару асимметричных ключей X25519 (приватный и публичный). Публичный ключ отправляется на сервер для того, чтобы другие пользователи могли начать с вами чат.</p>
</div>
</div>
<div class="step-item">
<div class="step-num">2</div>
<div class="step-content">
<h3>Деривация общего секрета (Shared Secret)</h3>
<p>Когда вы открываете чат, приложение берет ваш приватный ключ X25519 и публичный ключ собеседника, вычисляя общий секрет по алгоритму ECDH. Этот секретный ключ никогда не передается по сети — обе стороны вычисляют его независимо на своих девайсах.</p>
</div>
</div>
<div class="step-item">
<div class="step-num">3</div>
<div class="step-content">
<h3>Симметричное шифрование</h3>
<p>Все отправляемые текстовые сообщения шифруются по стандарту AES-256-GCM с уникальным вектором инициализации (Nonce). Полученный шифротекст передается на сервер.</p>
</div>
</div>
</div>
<h2 id="messagesCryptoHeader">Шифрование текстовых сообщений</h2>
<p>Каждое текстовое сообщение кодируется в массив байтов, после чего для него генерируется случайный 12-байтовый вектор инициализации (nonce). Данные шифруются на ключе sharedSecret по алгоритму AES-256-GCM. Результат представляет собой склеенный массив байтов: <code>nonce (12 байт) + mac (16 байт) + ciphertext (зашифрованный текст)</code>, закодированный в Base64.</p>
<div class="code-container" id="messageCode">
<pre><code>// Схематичный пример дешифровки сообщения на клиенте
Future&lt;String&gt; decryptMessage(String base64Data, SecretKey sharedKey) async {
final data = base64Decode(base64Data);
final nonce = data.sublist(0, 12);
final mac = data.sublist(12, 28);
final cipherText = data.sublist(28);
final decrypted = await aesGcm.decrypt(
SecretBox(cipherText, nonce: nonce, mac: Mac(mac)),
secretKey: sharedKey,
);
return utf8.decode(decrypted);
}</code></pre>
</div>
<h2 id="filesCryptoHeader">Поблочное шифрование медиафайлов</h2>
<p>Для предотвращения утечек данных при отправке медиафайлов (картинок, видео, голосовых заметок и документов), в Чепухаграм внедрена продвинутая поблочная система шифрования:</p>
<ol>
<li>При выборе файла генерируется случайный симметричный ключ файла (<code>fileKey</code>).</li>
<li>Ключ <code>fileKey</code> шифруется на общем ключе чата (<code>sharedSecret</code>) и отправляется на сервер как поле <code>encrypted_key</code>.</li>
<li>Сам файл считывается потоком и шифруется блоками по 64 КБ с использованием <code>fileKey</code>. К каждому зашифрованному блоку добавляется 4-байтовый заголовок, содержащий точную длину блока, и уникальный вектор инициализации с тегом аутентификации MAC.</li>
</ol>
<!-- Media block stream diagram -->
<h3>Архитектура поблочного крипто-стрима</h3>
<div class="block-stream-diagram">
<div class="stream-file">Исходный файл медиа</div>
<div class="stream-split">👇 Считывание блоками по 64 КБ</div>
<div class="stream-blocks">
<div class="stream-block">
<span class="block-title">Блок 1 (64 КБ)</span>
<div class="block-crypto">🔒 AES-256-GCM (fileKey)</div>
<div class="block-result">Длина (4б) + Nonce (12б) + Данные + MAC (16б)</div>
</div>
<div class="stream-block">
<span class="block-title">Блок 2 (64 КБ)</span>
<div class="block-crypto">🔒 AES-256-GCM (fileKey)</div>
<div class="block-result">Длина (4б) + Nonce (12б) + Данные + MAC (16б)</div>
</div>
<div class="stream-block tail">
<span class="block-title">Остаток (&lt;64 КБ)</span>
<div class="block-crypto">🔒 AES-256-GCM (fileKey)</div>
<div class="block-result">Длина (4б) + Nonce (12б) + Данные + MAC (16б)</div>
</div>
</div>
</div>
<div class="callout" id="fileSecurityNote">
<p><strong>Важно:</strong> Такой подход позволяет осуществлять потоковую дешифрацию медиа во время загрузки (стриминг), благодаря чему видео и аудиозаписи начинают воспроизводиться еще до полной загрузки файла.</p>
</div>
<h2 id="masterPassHeader">Резервная копия ключей и мастер-пароль</h2>
<p>Поскольку приватный ключ X25519 хранится в изолированном защищенном хранилище (Secure Storage) вашего смартфона, при переустановке приложения вы можете потерять доступ к переписке. Для предотвращения этого в Чепухаграм создана система защищенных резервных копий:</p>
<ul>
<li>Вы придумываете сложный <strong>Мастер-пароль</strong>.</li>
<li>На основе этого пароля с помощью алгоритма <strong>PBKDF2 (600 000 итераций, HMAC-SHA256, соль "chepuhagram_salt")</strong> генерируется ключ шифрования резервной копии.</li>
<li>Приватный ключ X25519 шифруется на этом ключе и отправляется на сервер как <code>encrypted_private_key</code>.</li>
<li>При входе на новом устройстве вы вводите мастер-пароль, приложение скачивает копию ключа, расшифровывает её на вашем устройстве, и вы снова можете читать все ваши чаты. Сервер видит только зашифрованный массив байт и не может его декодировать.</li>
</ul>
<h2 id="sessionSecurityHeader">Безопасность сессий и автозавершение</h2>
<p>Чепухаграм поддерживает одновременный вход на нескольких устройствах. Вся сессионная активность полностью подконтрольна пользователю:</p>
<p>При любом изменении пароля сквозного шифрования (или при полном сбросе ключей) все остальные активные сессии на сторонних девайсах автоматически инвалидируются на сервере и прекращают работу. Это защищает ваши чаты от несанкционированного доступа с ранее авторизованных устройств.</p>
</div>
<!-- Footer -->
<footer>
<div class="container">
<a href="../index.html" class="footer-logo">
<span class="logo-dot"></span>Чепухаграм
</a>
<p class="footer-text">Документ подготовлен техническим отделом Чепухаграм. Все криптографические операции соответствуют современным стандартам безопасности.</p>
</div>
</footer>
</body>
</html>