Передача зашифрованных данных по сети

Передача данных по сети без криптографической защиты приводит к возможности их перехвата, модификации и подмены. В контексте JavaScript-приложений одной из практичных библиотек для решения этих задач выступает Stanford JavaScript Crypto Library, предоставляющая готовые реализации симметричного шифрования, хеширования, генерации ключей и работы с форматами представления криптограмм.

При передаче зашифрованной информации по сети используется следующая последовательность:

  1. Формирование исходного сообщения (JSON, строка, бинарные данные).
  2. Генерация или получение ключа шифрования.
  3. Шифрование данных на клиенте.
  4. Сериализация криптограммы в транспортируемый формат.
  5. Отправка через HTTP/WebSocket.
  6. Расшифрование на стороне получателя.

Ключевая особенность SJCL заключается в том, что библиотека оперирует структурой криптограммы, включающей:

  • iv — вектор инициализации
  • salt — соль для производных ключей
  • ct — зашифрованный текст
  • iter — количество итераций PBKDF2
  • ks — размер ключа
  • v — версия формата

Шифрование данных перед отправкой

SJCL предоставляет высокоуровневые функции encrypt и decrypt, упрощающие работу с AES в режиме CCM.

Пример шифрования JSON-объекта перед передачей:

import sjcl from "sjcl";

const message = {
  userId: 42,
  action: "transfer",
  amount: 1000
};

const json = JSON.stringify(message);
const password = "strong-password";

// Шифрование
const encrypted = sjcl.encrypt(password, json);

// Результат — строка JSON с криптограммой
console.log(encrypted);

Функция sjcl.encrypt автоматически:

  • генерирует соль и IV
  • применяет PBKDF2 для получения ключа
  • использует AES-CCM
  • формирует JSON-криптограмму

Формат криптограммы и сериализация

Результат шифрования представляет собой JSON-строку:

{
  "iv":"...",
  "v":1,
  "iter":10000,
  "ks":128,
  "ts":64,
  "mode":"ccm",
  "adata":"",
  "cipher":"aes",
  "salt":"...",
  "ct":"..."
}

Для передачи по сети такая структура может отправляться напрямую или дополнительно кодироваться.

Отправка через HTTP

fetch("https://api.example.com/secure-endpoint", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: encrypted
});

На сервере ожидается получение той же структуры для последующего расшифрования.

Дешифрование полученных данных

На стороне получателя выполняется обратная операция:

const decrypted = sjcl.decrypt(password, encrypted);
const data = JSON.parse(decrypted);

console.log(data);

Важно, что пароль должен совпадать, а криптограмма должна оставаться неизменной. Любая модификация iv, salt или ct приводит к невозможности восстановления данных.

Использование ключей вместо пароля

В более контролируемых системах вместо строкового пароля применяется заранее сгенерированный ключ.

SJCL поддерживает работу с битовыми массивами:

const key = sjcl.random.randomWords(4); // 128-bit key

const encrypted = sjcl.encrypt(key, json);
const decrypted = sjcl.decrypt(key, encrypted);

Такой подход исключает необходимость PBKDF2 и ускоряет операции.

Передача через WebSocket

Для потоковой передачи данных используется WebSocket, где каждая криптограмма отправляется как отдельное сообщение.

const socket = new WebSocket("wss://api.example.com");

socket.ono pen = () => {
  const payload = sjcl.encrypt(password, json);
  socket.send(payload);
};

socket.onmess age = (event) => {
  const decrypted = sjcl.decrypt(password, event.data);
  console.log(JSON.parse(decrypted));
};

WebSocket особенно эффективен для:

  • чатов
  • финансовых потоков
  • телеметрии
  • обмена событиями в реальном времени

Контроль целостности данных

SJCL использует AES-CCM, который обеспечивает не только конфиденциальность, но и аутентификацию сообщения.

Поле ts (tag size) определяет длину аутентификационного тега. При расшифровании библиотека автоматически проверяет целостность данных.

При любом изменении ciphertext происходит исключение:

try {
  sjcl.decrypt(password, tamperedData);
} catch (e) {
  console.error("Нарушена целостность данных");
}

Использование нестандартного формата передачи

В некоторых системах JSON-криптограмма не подходит из-за объёма. Тогда применяется бинарная или компактная сериализация.

Пример преобразования в строку Base64:

const encryptedObj = sjcl.encrypt(password, json);
const base64 = btoa(encryptedObj);

fetch("/endpoint", {
  method: "POST",
  body: base64
});

И обратное восстановление:

const encryptedObj = atob(base64);
const decrypted = sjcl.decrypt(password, encryptedObj);

Потоковая модель передачи данных

При работе с большими объёмами данных применяется разбиение на блоки:

function encryptChunk(chunk, key) {
  return sjcl.encrypt(key, chunk);
}

const chunks = [
  "part1",
  "part2",
  "part3"
];

const encryptedChunks = chunks.map(c => encryptChunk(c, password));

Каждый блок шифруется независимо, что позволяет:

  • параллелить обработку
  • восстанавливать поток при потере пакетов
  • избегать переполнения памяти

Использование дополнительных параметров шифрования

SJCL позволяет управлять параметрами криптографии:

const options = {
  mode: "ccm",
  iter: 20000,
  ts: 128,
  ks: 256
};

const encrypted = sjcl.encrypt(password, json, options);

Параметры:

  • iter — стойкость PBKDF2 (увеличивает стоимость brute-force)
  • ks — размер ключа AES (128, 192, 256)
  • ts — размер аутентификационного тега

Увеличение этих значений повышает безопасность, но снижает производительность.

Обработка ошибок при передаче

При сетевой передаче криптограммы часто возникают следующие ошибки:

  • повреждение JSON
  • потеря символов при кодировании
  • несоответствие версии SJCL
  • неправильный пароль

Пример обработки:

function safeDecrypt(data, password) {
  try {
    return JSON.parse(sjcl.decrypt(password, data));
  } catch (e) {
    return null;
  }
}

Интеграция с REST API

В типичной архитектуре клиент шифрует данные перед отправкой:

async function sendSecure(data, password) {
  const encrypted = sjcl.encrypt(password, JSON.stringify(data));

  return await fetch("/api/secure", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: encrypted
  });
}

Сервер получает уже зашифрованный payload и не имеет доступа к содержимому без ключа.

Передача ключей и модель угроз

Критическим моментом является способ передачи ключа шифрования. SJCL не решает задачу распределения ключей, поэтому применяются дополнительные подходы:

  • предварительный обмен ключами через TLS
  • асимметричное шифрование ключа
  • derivation из пароля пользователя
  • использование серверного key management

Передача ключа в открытом виде полностью нивелирует криптографическую защиту.

Использование случайности и генерации IV

SJCL использует криптографически стойкий генератор случайных чисел:

sjcl.random.addEntropy(window.crypto.getRandomValues(new Uint32Array(32)));

IV (initialization vector) генерируется автоматически при каждом шифровании, что предотвращает повторяемость ciphertext при одинаковых входных данных.

Совместимость и переносимость данных

Криптограммы SJCL являются самодостаточными и могут:

  • передаваться между различными платформами
  • сохраняться в базе данных
  • использоваться в офлайн-режиме
  • восстанавливаться независимо от среды выполнения

При этом важно сохранять полную JSON-структуру без изменений.

Потенциальные проблемы при сетевой передаче

При использовании SJCL в сетевых сценариях возникают типичные ограничения:

  • увеличение размера данных (≈ +30–50%)
  • зависимость от синхронизации параметров шифрования
  • необходимость строгой сериализации
  • чувствительность к повреждению структуры JSON

Эти особенности требуют аккуратного проектирования протокола передачи.

Архитектура защищённого обмена сообщениями

Типичная схема выглядит следующим образом:

  • Клиент → шифрует данные SJCL
  • Клиент → отправляет JSON-криптограмму
  • Сервер → принимает данные без интерпретации
  • Сервер → расшифровывает при наличии ключа
  • Сервер → обрабатывает чистые данные

При обратной связи процесс повторяется в обратном направлении, обеспечивая двустороннюю защищённую коммуникацию.