Skip to content

0x0FACED/zec

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

81 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZEC - Зашифрованный контейнер секретов

ZEC (Zipped Encrypted Container) — это контейнерная система для безопасного хранения секретов в зашифрованном виде. Все секреты хранятся в файлах с расширением *.zec.

Основная концепция

Идея заключается в хранении секретов в сжатом и зашифрованном виде. При чтении файла загружаются только заголовок и индексная таблица, что позволяет узнать содержимое контейнера без чтения самих секретов.

Ключевые особенности:

  • Безопасность: Все данные зашифрованы алгоритмом ChaCha20-Poly1305
  • Эффективность: Читается только необходимая информация
  • Целостность: Проверка чексуммы всего файла
  • Аутентификация: HMAC проверка пароля

Архитектура системы

Криптографическая схема

1. Формирование ключей

  1. Пароль пользователя → Argon2id → Master Key (32 байта)

    • Используется соль 16 байт
    • Параметры по умолчанию: память 256KB, итерации 5, параллелизм 1
  2. Master Key → Генерация и шифрование → Encrypted FEK (60 байт)

    • Генерируется случайный FEK (File Encryption Key) 32 байта
    • FEK шифруется Master Key с помощью ChaCha20-Poly1305
    • Результат: nonce(12) + ciphertext(32) + auth_tag(16) = 60 байт
  3. Master Key → HMAC → Verification Tag (16 байт)

    • Вычисляется HMAC от аутентифицируемых полей заголовка
    • Используется для проверки правильности пароля

2. Шифрование секретов

Для небольших данных (текст):

  • Режим: ChaCha20-Poly1305 (AEAD)
  • Nonce: 12 байт (случайный для каждого секрета)
  • Ключ: FEK
  • Результат: зашифрованные данные с встроенным тегом аутентификации

Для больших файлов:

  • Режим: XChaCha20-Poly1305 (потоковое шифрование)
  • Nonce: 24 байта (базовый nonce + счетчик блока)
  • Размер блока: 128KB
  • Каждый блок шифруется отдельно с уникальным nonce

Структура файла

┌─────────────────────────┐ ← offset 0
│      File Header        │ (256 байт, фиксированный размер)
│      (всегда открыт)    │
├─────────────────────────┤ ← offset 256
│   Зашифрованный         │
│      Секрет #1          │ (размер переменный)
├─────────────────────────┤
│   Зашифрованный         │
│      Секрет #2          │ (размер переменный)
├─────────────────────────┤
│         ...             │
├─────────────────────────┤ ← IndexTableOffset
│  Зашифрованная          │
│  Индексная таблица      │ (содержит метаданные всех секретов)
└─────────────────────────┘ ← конец файла

Заголовок файла (256 байт)

type Header struct {
    Version          uint8     // Версия формата файла (0x01)
    Flags            uint8     // Флаги состояния (завершен, зашифрован, сжат)
    EncryptionAlgo   uint8     // Алгоритм шифрования (1 = ChaCha20)
    ArgonMemoryLog2  uint8     // log2(память в KB) для Argon2
    SecretCount      uint32    // Количество секретов
    CreatedAt        int64     // Время создания (unix timestamp)
    ModifiedAt       int64     // Время последней модификации
    DataSize         uint64    // Общий размер всех секретов
    OwnerID          [16]byte  // UUID владельца файла
    ArgonSalt        [16]byte  // Соль для Argon2
    ArgonIterations  uint16    // Количество итераций Argon2
    ArgonParallelism uint8     // Параллелизм Argon2
    _                uint8     // Байт выравнивания
    Checksum         [32]byte  // SHA256 чексумма всего файла
    VerificationTag  [16]byte  // HMAC для проверки пароля
    EncryptedFEK     [60]byte  // Зашифрованный FEK
    IndexTableOffset uint64    // Смещение индексной таблицы
    IndexTableNonce  [12]byte  // Nonce для шифрования индекса
    Reserved         [60]byte  // Резерв для будущих расширений
}

Метаданные секрета (94 байта)

type SecretMeta struct {
    Name        [32]byte  // Имя секрета (фиксированный размер)
    Offset      uint64    // Смещение в файле
    Size        uint64    // Размер зашифрованных данных
    CreatedAt   uint64    // Время создания
    ModifiedAt  uint64    // Время изменения
    Type        uint8     // Тип: 1=текст, 2=файл, 3=бинарные данные
    Flags       uint8     // Флаги: завершен, зашифрован, сжат, удален
    _           [1]byte   // Выравнивание
    Nonce       [24]byte  // IV для шифрования (12 или 24 байта)
    EncryptMode uint8     // Режим шифрования: 1=AEAD, 2=потоковый
}

Алгоритмы работы

Создание нового контейнера

  1. Инициализация:

    Пользователь → пароль → Argon2id(пароль, соль, параметры) → Master Key
    
  2. Генерация ключей:

    Генерация FEK (32 случайных байта)
    ChaCha20(Master Key, nonce) → Encrypted FEK
    HMAC(Master Key, заголовок) → Verification Tag
    
  3. Создание заголовка:

    • Заполнение всех полей структуры Header
    • Установка флагов, времени, параметров Argon2
    • Запись заголовка в начало файла

Добавление секрета

  1. Подготовка:

    • Проверка пароля через Verification Tag
    • Расшифровка FEK из Encrypted FEK
  2. Шифрование данных:

    Для текста:
    ChaCha20-Poly1305(FEK, nonce_12, данные) → зашифрованные_данные
    
    Для файлов:
    XChaCha20-Poly1305_Stream(FEK, nonce_24, поток_данных) → зашифрованный_поток
    
  3. Запись в контейнер:

    • Поиск конца данных (после последнего секрета)
    • Запись зашифрованных данных
    • Создание метаданных SecretMeta
    • Добавление в индексную таблицу
  4. Обновление метаинформации:

    • Увеличение SecretCount в заголовке
    • Обновление DataSize
    • Пересчет и запись новой чексуммы

Чтение секрета

  1. Аутентификация:

    Пароль → Argon2id → Master Key
    HMAC(Master Key, заголовок) == Verification Tag ?
    Если да: Master Key правильный
    
  2. Получение FEK:

    ChaCha20-Poly1305.Decrypt(Master Key, Encrypted FEK) → FEK
    
  3. Поиск секрета:

    • Расшифровка индексной таблицы с помощью FEK
    • Поиск секрета по имени в индексе
    • Получение offset и size
  4. Расшифровка данных:

    Переход к offset в файле
    Чтение size байт зашифрованных данных
    
    Для AEAD режима:
    ChaCha20-Poly1305.Decrypt(FEK, nonce, данные) → исходные_данные
    
    Для потокового режима:
    XChaCha20-Poly1305_Stream.Decrypt(FEK, nonce, поток) → исходный_поток
    

Удаление секрета

Мягкое удаление (soft delete)

  • Установка флага FlagDeleted в метаданных
  • Секрет остается в файле, но помечается как удаленный
  • Не показывается в списках

Принудительное удаление (force delete) с дефрагментацией

Проблема: После удаления секрета в файле остается "дыра"

[Header][Secret1][Secret2][Secret3][Index] → удаляем Secret2
[Header][Secret1][  ???  ][Secret3][Index] ← дыра в файле

Решение: Дефрагментация со сдвигом данных влево

  1. Зануление удаляемой области:

    for remain > 0 {
        // Записываем нули блоками по 4MB
        seek(удаляемый_offset + позиция)
        write(нулевой_буфер[размер_блока])
        позиция += размер_блока
        remain -= размер_блока
    }
  2. Сдвиг секретов влево:

    for каждый_секрет_после_удаленного {
        // Читаем блоками и переписываем левее
        for remain > 0 {
            seek(исходный_offset)
            read(буфер[размер_блока])
            
            seek(новый_offset)
            write(буфер[размер_блока])
            
            исходный_offset += размер_блока
            новый_offset += размер_блока
        }
        
        // Обновляем offset в метаданных
        секрет.Offset = новый_offset_секрета
    }
  3. Обрезка файла:

    новый_конец = максимальный_offset + размер_последнего_секрета
    truncate(файл, новый_конец)
  4. Обновление метаданных:

    • Удаление записи из индексной таблицы
    • Уменьшение SecretCount и DataSize
    • Пересчет чексуммы

Проверка целостности

  1. Вычисление чексуммы:

    hasher = SHA256.New()
    
    // Хешируем заголовок БЕЗ поля Checksum
    hasher.Write(заголовок_до_checksum)
    hasher.Write([32]byte{0}) // нули вместо checksum
    hasher.Write(заголовок_после_checksum)
    
    // Хешируем все данные после заголовка
    seek(256) // после заголовка
    for блок := range все_данные {
        hasher.Write(блок)
    }
    
    computed_checksum = hasher.Sum()
  2. Сравнение:

    if computed_checksum != header.Checksum {
        return ОшибкаЦелостности
    }

Процедуры сохранения

Полный цикл Save()

  1. Подготовка индексной таблицы:

    payload_end = максимальный(секрет.Offset + секрет.Size)
    header.IndexTableOffset = payload_end
    
  2. Пересчет HMAC:

    header.VerificationTag = HMAC(Master Key, header.AuthenticatedBytes())
    
  3. Шифрование и запись индекса:

    зашифрованный_индекс = ChaCha20(FEK, IndexTableNonce, сериализованный_индекс)
    seek(IndexTableOffset)
    write(зашифрованный_индекс)
    
  4. Установка флагов завершения:

    header.Flags = FlagCompleted | FlagEncrypted
    
  5. Двухэтапная запись заголовка:

    // Этап 1: запись без чексуммы
    header.Checksum = [32]byte{0}
    seek(0)
    write(header)
    
    // Вычисление чексуммы всего файла
    checksum = вычислить_SHA256_всего_файла()
    
    // Этап 2: запись с правильной чексуммой
    header.Checksum = checksum
    seek(0)
    write(header)
    
  6. Синхронизация:

    file.Sync() // принудительная запись на диск
    

Безопасность

Защита от атак

  1. Перебор паролей: Затруднен Argon2id с настраиваемой сложностью
  2. Изменение данных: Обнаруживается через чексумму SHA256
  3. Подмена секретов: Невозможна из-за AEAD тегов аутентификации
  4. Анализ трафика: Все данные зашифрованы, включая метаданные

Криптографические гарантии

  • Конфиденциальность: ChaCha20 с 256-битными ключами
  • Аутентичность: Poly1305 теги для каждого секрета
  • Целостность: SHA256 чексумма всего контейнера
  • Неотказуемость: HMAC подпись мастер-ключом

Управление ключами

  • Пароли не хранятся в открытом виде
  • FEK генерируется криптостойким ГПСЧ
  • Каждый секрет имеет уникальный nonce
  • Master Key выводится детерминированно из пароля

Производительность

Оптимизации

  1. Ленивая загрузка: Читается только заголовок и индекс
  2. Потоковое шифрование: Большие файлы обрабатываются блоками
  3. Блочные операции: Дефрагментация работает блоками 4MB
  4. Прогресс-индикаторы: Для длительных операций

Масштабируемость

  • Поддержка файлов до петабайт
  • Эффективная работа с тысячами секретов
  • Минимальное потребление памяти
  • Инкрементальные обновления

Использование CLI

# Создание нового контейнера
./zec new --file=my_secrets

# Добавление текстового секрета
./zec add --file=my_secrets --name=api_key --payload="secret_key_123"

# Добавление файла
./zec add --file=my_secrets --name=backup --payload="/path/to/backup.tar.gz"

# Просмотр содержимого
./zec list --file=my_secrets

# Чтение секрета
./zec get --file=my_secrets --name=api_key

# Экспорт файла
./zec get --file=my_secrets --name=backup --out=./restored_backup.tar.gz

# Удаление секрета (мягкое)
./zec rm --file=my_secrets --name=old_key

# Принудительное удаление с дефрагментацией
./zec rm --file=my_secrets --name=large_file --force

# Просмотр заголовка файла
./zec header --file=my_secrets

Планы развития

Текущие возможности

  • ✅ Создание и управление контейнерами
  • ✅ Шифрование ChaCha20-Poly1305
  • ✅ Потоковое шифрование больших файлов
  • ✅ Дефрагментация при удалении
  • ✅ Проверка целостности
  • ✅ CLI интерфейс

Планируемые улучшения

  • 🔄 Рефакторинг в чистую библиотеку
  • 📱 Web интерфейс
  • 🔧 Интерактивная оболочка
  • 🤖 Агент для управления сессиями
  • 🗜️ Сжатие данных (zstd)
  • 🔐 Дополнительные алгоритмы шифрования
  • ☁️ Поддержка облачных хранилищ
  • 👥 Многопользовательский режим

Техническое резюме

ZEC реализует современный подход к безопасному хранению секретов, сочетая:

  • Криптографически стойкие алгоритмы (ChaCha20, Argon2, HMAC)
  • Эффективную файловую структуру с индексированием
  • Надежную дефрагментацию при удалении данных
  • Полную проверку целостности
  • Удобный пользовательский интерфейс

Система спроектирована для обеспечения максимальной безопасности при сохранении высокой производительности и удобства использования.

About

[Training project] A safe cli tool to store your secrets (plain text of files)

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages