Загрузка...

Взломай меня, если сможешь: шифрование на эмбеддингах

Тема в разделе Статьи создана пользователем доза 5 май 2025. 441 просмотр

Загрузка...
  1. доза
    доза Автор темы 5 май 2025 Заблокирован(а) 388 4 июл 2022
    [IMG]


    [IMG]
    Привет, читатель.
    Статья больше про исследование и тестирование метода, я не пытаюсь навязать все нижеописанное и не заявляю что это 100% рабочее шифрование. Но как по мне идея шифрования через обобщение нейросетей достойна внимания.


    Обзор метода.
    Само сообщение шифруется через симметричное шифрование AES-CBC, где нужен ключ (16 байт) и IV (начальный вектор, чтобы шифр был разным). Ключ генерируется из эмбеддингов, полученных моделью. Но особенность метода в том, что изображение не является секретом, любой желающий может увидеть изображение и зашифрованное сообщение. Но при этом изображение не является публичным ключом. Ключ может получить только конкретная модель нейросети.

    Поэтому чтобы это работало, yolo-seg должен быть обучен на своем датасете. Одна и та же модель должна быть у обоих участников. Веса модели и датасет должны храниться в строгом секрете.

    Любой человек в здравом уме скажет, что yolo не сможет уникально сегментировать изображения и на этом моменте закроет статью.
    Эмбеддинги из 4 и 16 слоя это 192 числа, типа float32, обычно в диапазоне от -10 до 10. Самый важный момент, который позволяет создать уникальный ключ для каждого изображения. По крайней мере это позволяет учитывать малейшие изменения в изображении. Учитывается все изображение, сам класс и его фон. Даже если меняется всего 1 пиксель, создается уникальный ключ.

    Провел тест из 1000 одинаковых изображений где рандомно заменены 1-5 пикселей. Результат в статье.

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

    Чтобы расшифровать сообщение нужно получить изображение, на основе которого был получен ключ и само зашифрованное сообщение. Через такую же модель yolo-seg получаются эмбеддинги чтобы повторить ключ.


    Эмбеддинги yolo11n-seg.



    В основе метода лежит использование эмбеддингов, полученных из модели YOLO11n-seg, для генерации ключа из изображения. Эмбеддинги представляют собой числовое описание изображения, которое позволяет учесть как общие характеристики (например, объект на изображении), так и мелкие детали (изменение одного пикселя). В этом разделе я подробно объясню, что такое эмбеддинги, как они формируются в модели YOLO11n-seg, почему выбраны слои 4 и 16, как обеспечивается их чувствительность к изменениям изображения и как они используются для

    Эмбеддинги — это компактное числовое представление изображения, которое извлекается из внутренних слоёв нейронной сети. В контексте метода они являются результатом обработки изображения моделью yolo11n-seg и представляют собой массив из 192 чисел с плавающей запятой (float32). Эти числа описывают различные аспекты изображения: объект (например, кот), фон, текстуры, края и даже отдельные пиксели. Каждое число отражает вклад определённой особенности изображения, выявленной нейросетью. Но самое важное что каждое число имеет свой диапазон влияния. И этот уровень влияния определяется датасетом, обучением, разметкой, пайлпайном обучения и инференса.​
    В моём методе эмбеддинги состоят из двух частей:

    64 числа из 16 слоя, Описывает более крупные структуры, такие как форма класса, его цвет.

    Диапазон значений чисел обычно находится в пределах от -10 до 10, хотя в зависимости от изображения и характеристик модели значения могут быть больше или меньше. Например, типичный фрагмент эмбеддингов для изображения кота может выглядеть следующим образом:
    [0.1234, -0.5678, 1.2345, -0.0987, 2.3456, 0.6789, -1.5432, 0.4321, ...]

    Если изменить один пиксель изображения, например, с [100, 100, 100] на [101, 100, 100], некоторые числа в эмбеддингах слегка изменятся:​
    [0.1235, -0.5678, 1.2344, -0.0987, 2.3457, 0.6789, -1.5431, 0.4321, ...]

    Эти небольшие изменения играют ключевую роль: они обеспечивают чувствительность метода к минимальным различиям в изображении. Это позволяет генерировать уникальный ключ для каждой версии изображения.

    Формирование эмбеддингов.

    YOLO11n-seg изначально нейронная сеть, предназначенная для обнаружения и сегментации объектов. Она состоит из 23 слоёв, каждый из которых обрабатывает изображение на разном уровне абстракции. В моём методе я использую не итоговые маски сегментации, а промежуточные активации двух слоёв — 4 и 16, которые извлекаются во время обработки изображения.

    Сперва загружается изображение.

    Изображение (maryJane.png размером 1088x1920 пикселей) загружается и преобразуется в тензор с тремя каналами (RGB). Тензор имеет размер [1, 3, 1088, 1920], где:

    • 128 чисел из 4 слоя. Отвечает за мелкие детали изображения, фон
    • 1 количество изображений,
    • 3 каналы цвета,
    • 1088 потому что 1080 не кратно 32, а самое близкое число 1088. Это связано с архитектурой модели.
    Обработка через yolo11n-seg.
    Модель прогоняет тензор через свои слои. Каждый слой выполняет операции свёртки, нормализации и активации, создавая всё более абстрактные представления изображения.
    На выходе слоя 4 получается тензор размером [1, 128, 34, 60], где:

    • 128 — количество каналов,
    • 34x60 — уменьшенное пространственное разрешение изображения.

    • На выходе слоя 16 — тензор [1, 64, 17, 30], где:
      • 64 — каналы,
      • 17x30 — ещё меньшее разрешение.
    Извлечение активаций.
    Я использую механизм хуков (register_forward_hook) для получения активаций слоёв 4 и 16 во время обработки изображения. Это позволяет заглянуть внутрь модели и извлечь промежуточные данные, которые более уникальны чем итоговый результат сегментации.
    activations = {}
    layers[4].register_forward_hook(lambda m, i, o: activations.update({"layer_4": o}))
    layers[16].register_forward_hook(lambda m, i, o: activations.update({"layer_16": o}))
    with torch.no_grad():
    model(image, conf=0.4, imgsz=(1088, 1920))
    Усреднение активаций.
    Чтобы получить массив из 192 чисел (128 + 64), активации каждого слоя усредняются по пространственным измерениям (высоте и ширине).

    • Для слоя 4: тензор [1, 128, 34, 60] → массив [128] Усреднение по 34x60,
    • Для слоя 16: тензор [1, 64, 17, 30] → массив [64] Усреднение по 17x30

      embeddings = [activations[k].mean(dim=[2, 3]) for k in ["layer_4", "layer_16"]]
    Округление.
    На разных системах результат может отличаться. Вычисления на GPU и CPU дают разные результаты. Поэтому они округляются до 4 знаков после запятой. Это по прежнему сохраняет устойчивость к изменению даже 1 пикселя.

    flat_embeddings = np.round(torch.cat(embeddings).cpu().numpy(), decimals=4)
    Почему выбраны слои 4 и 16?
    Выбор слоёв 4 и 16 не случаен.

    • Слой 4: Ранний слой модели, который обрабатывает изображение на низком уровне. Он чувствителен к мелким деталям, таким как отдельные пиксели, края, текстуры и локальные цветовые переходы. Активации слоя 4 содержат 128 каналов, что позволяет уловить широкий спектр низкоуровневых признаков.
    • Слой 16: Более глубокий слой, который анализирует изображение на высоком уровне. Он распознаёт крупные структуры, такие как форма объекта (например, кота), его поза и общий контекст сцены. Активации слоя 16 содержат 64 канала, что достаточно для описания объектов, но менее детализировано, чем слой 4.


    • Возможно стоит попробовать комбинации других слоев, но с этими все в порядке пока что. Меня результат удовлетворил.
    Чувствительность YOLO11n-seg.
    Изменение одного пикселя, например с [100, 100, 100] на [101, 100, 100]) влияет на активации слоя 4, потому что он анализирует локальные детали. Это изменение распространяется на тензор [1, 128, 34, 60], слегка сдвигая некоторые значения.

    Слой 16 менее чувствителен к отдельным пикселям, но может уловить изменения, если они влияют на форму объекта или контекст

    После усреднения сдвиг в активациях приводит к изменению одного или нескольких чисел в эмбеддингах.

    Работа с SHA-256.
    Эмбеддинги (192 числа) преобразуются в байты и хешируются с помощью SHA-256.

    SHA-256 чувствителен к входным данным, изменение одного числа в эмбеддингах на 0.0001 приводит к совершенно другому хешу. Это гарантирует, что ключ и IV для каждой версии изображения будут уникальными.

    hash_digest = hashlib.sha256(flat_embeddings.tobytes()).digest()
    key = hash_digest[:16] # Ключ (16 байт)
    iv = hash_digest[16:32] # IV (16 байт)
    Пример.


    • Исходное изображение, эмбеддинги [0.1234, -0.5678, 1.2345, ...]. Ключ c87bce1c05dd27f6f9c256399c43aade.
    Изображение с изменённым пикселем, эмбеддинги [0.1235, -0.5678, 1.2344, ...]. Ключ 1279567999291717328cd268d7bde881.

    Тестирование уникальности ключа.

    Как обсуждалось выше, ключевая проблема, уникальность ключей для каждого изображения.
    Чтобы проверить метод я сгенерировал 1000 копий изображений своей кошки, заменив на каждом по 1-5 пикселей рандомно, RGB-значения выбирались случайно.
    random.randint(0, 255),
    random.randint(0, 255),
    random.randint(0, 255)
    )
    elif modified_img.mode == 'RGBA':
    new_color = (
    random.randint(0, 255),
    random.randint(0, 255),
    random.randint(0, 255),
    pixels[x, y][3] # Сохраняем альфа-канал
    )
    else:
    # Для других режимов (например, grayscale) преобразуем в RGB
    modified_img = modified_img.convert('RGB')
    pixels = modified_img.load()
    new_color = (
    random.randint(0, 255),
    random.randint(0, 255),
    random.randint(0, 255)
    )

    # Изменяем пиксель
    pixels[x, y] = new_color

    # Сохраняем результат
    base_name = os.path.splitext(os.path.basename(image_path))[0]
    output_path = os.path.join(output_dir, f"{base_name}_mod_{i+1}.{img_format.lower()}")
    modified_img.save(output_path, format=img_format)

    print(f"Создано: {output_path} (изменено {num_pixels_to_change} пикселей)")

    if __name__ == "__main__":
    input_image = "images/maryJane.png" # Путь к исходному изображению
    output_directory = "new_images" # Папка для сохранения результатов
    num_iterations = 1000 # Количество изображений для генерации

    modify_random_pixels(input_image, output_directory, num_iterations)
    Как только изображения сгенерировались, запускаю код который симулирует работу шифрования, а в конце сравнивает результаты. Если хотя бы 1 раз результаты повторятся, метод не рабочий. Можно попробовать учесть эмбеддинги из еще одного слоя, но пока нет нужды делать этого не нужно.

    Мы все прекрасно понимаем, что метод и так не рабочий, рано или поздно копии ключей случатся, но ведь интересно когда это случится. По большей части это обусловлено обучением и датасетом, чем больше и разнообразнее тем лучше результат в плане уникальности в теории. Но есть еще очень большое количество параметров, которые могут влиять на это.



    Размер обучаемой модели.
    Разнообразие датасета и общее количество изображений.
    Качество разметки.
    Пайплайн обучения.
    Пайплайн инференса.

    print("\n=== Результаты теста ===")
    print(f"Обработано изображений: {len(results)}")
    print(f"Уникальных ключей: {len(key_to_images)}")

    duplicates_found = False
    for key, images in key_to_images.items():
    if len(images) > 1:
    duplicates_found = True
    print(f"\nОШИБКА: Одинаковый ключ найден для {len(images)} изображений!")
    print(f"Ключ: {key}")
    print("Изображения:")
    for img in images:
    print(f" - {img}")

    if not duplicates_found:
    print("\nУСПЕХ: Все ключи уникальны! Метод прошёл тест.")
    else:
    print("\nПРОВАЛ: Найдены одинаковые ключи. Метод недостаточно чувствителен!")

    # Выводим все результаты
    print("\nПодробные результаты:")
    for result in results:
    print(f"Изображение: {result['image']}")
    print(f" Ключ: {result['key']}")
    print(f" IV: {result['iv']}")
    print(f" Шифротекст: {result['ciphertext']}\n")

    return results, duplicates_found

    # Основной код
    device = torch.device("cpu")
    model = YOLO("yolo11n-seg.pt").to(device)
    image_folder = "modified_images" # Папка с 1000 изображениями
    message = "doza_pidor".encode()
    delay = 0.5 # Задержка в секундах

    results, duplicates_found = test_images(image_folder, model, message, delay)
    [IMG]
    Тестирование пройдено успешно, 0 копий. В следующем попробую собрать просто разные, но похожие изображения, без замены пикселей. Для меня такой результат говорит о том что метод имеет место быть или как минимум еще одно тестирование можно провести.

    Про безопасность.

    В своей статье я опираюсь на результаты предобученной модели yolo11n-seg. В боевых условия учить ее нужно самому, на кастомном датасете, объяснять думаю не нужно.
    Датасет частично должен быть собран в реальной жизни буквально. Можно шифроваться на чем угодно. Какие самые популярные изображения в сети ? Голые девки и кошки. Уловили ? Идете на улице и делаете фотографии котов Затем мешаете с фотографиями из сети, желательно так чтобы зацепить в датасет как можно больше пород.


    Понимаю, что это та еще задница, но метод считается "околобезопасным" только при таких условиях.
    Если размечать лень берите самую маленькую модель и делайте сегментацию на 500 изображениях. Тут можно сделать разметку намеренно криво, в теории признаки должны стать более непредсказуемыми. А чтобы модель сегментировала все изображения, то нужно выкрутить conf=0.2, так появится неуверенная, кривая, непредсказуемая сегментация.
    Даже если второе тестирование будет тоже успешным и получится доказать решение проблем с коллизией окончательно. То это не отменяет того факта, что если атакующий получит доступ к модели, то вся переписка тут же будет расшифрована. Поэтому ему нужна не только модель, но и пайплайн инференса и вообще код в целом. Иначе взлом шифра займет какое то время. Откуда атакующий узнает про 4 и 16 слой ? Из этой статьи, но это уже другая история.

    Реализация.
    В предыдущих разделах я описал, как эмбеддинги, полученные из модели yolo11n-seg, используются для генерации ключа. Теперь я опишу полный код шифрования и расшифровки, а затем подробно объясню, как он работает, опираясь на принципы, описанные ранее.
    Код показывает, как изображение превращается в ключ для шифрования сообщения через AES-CBC, и как то же изображение используется для расшифровки.

    Шифрование.
    import cv2
    import numpy as np
    import torch
    from ultralytics import YOLO
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import pad
    import hashlib

    # Настройка детерминизма
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    torch.use_deterministic_algorithms(True)

    def generate_key_and_iv(embeddings):
    flat_embeddings = torch.cat([e.flatten() for e in embeddings]).cpu().numpy()
    flat_embeddings = np.round(flat_embeddings, decimals=4)
    hash_digest = hashlib.sha256(flat_embeddings.tobytes()).digest()
    return hash_digest[:16], hash_digest[16:32]

    def encrypt_data(data, key, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    ct_bytes = cipher.encrypt(pad(data, AES.block_size))
    return ct_bytes

    def process_image(image_path, model):
    image = cv2.imread(image_path)
    if image is None:
    raise ValueError("Не удалось загрузить изображение!")
    original_shape = image.shape[:2]
    yolo_size = (max(32, (original_shape[0] + 31) // 32 * 32), max(32, (original_shape[1] + 31) // 32 * 32))
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.uint8)
    image_tensor = torch.from_numpy(image_rgb).permute(2, 0, 1).float() / 255.0
    image_tensor = image_tensor.clamp(0.0, 1.0).unsqueeze(0).to(model.device)
    activations = {}
    def get_activation(name):
    def hook(module, input, output):
    activations[name] = output
    return hook
    layers = model.model.model
    layers[4].register_forward_hook(get_activation("layer_4"))
    layers[16].register_forward_hook(get_activation("layer_16"))
    with torch.no_grad():
    results = model(image, conf=0.4, imgsz=yolo_size)
    embeddings = []
    for layer_name in ["layer_4", "layer_16"]:
    activation = activations.get(layer_name, torch.zeros(1))
    embedding = activation.mean(dim=[2, 3]) if len(activation.shape) == 4 else torch.zeros(1)
    embeddings.append(embedding)
    return embeddings

    # Шифрование
    device = torch.device("cpu")
    model = YOLO("yolo11n-seg.pt").to(device)
    image_path = "images/maryJane.png"
    message = "doza_pidor".encode()

    embeddings = process_image(image_path, model)
    key, iv = generate_key_and_iv(embeddings)
    ct_bytes = encrypt_data(message, key, iv)

    # Сохранение шифротекста и IV
    with open("ciphertext.bin", "wb") as f:
    f.write(iv + ct_bytes) # IV (16 байт) + шифротекст

    print("Ключ:", key.hex())
    print("IV:", iv.hex())
    print("Шифротекст:", ct_bytes.hex())
    Код реализует метод шифрования, описанный в статье, и состоит из трёх ключевых функций:

    • Обработка изображения (process_image),
    • Генерация ключа и IV (generate_key_and_iv),
    • Шифрование и расшифровка (encrypt_data, decrypt_data). Я разберу каждую часть, связав её с предыдущими разделами.
    Настройка детерминизма.
    В начале кода включается детерминизм для PyTorch, чтобы эмбеддинги были одинаковыми на разных системах.


    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    torch.use_deterministic_algorithms(True)

    Как писал ранее в разделе про эмбеддинги, это устраняет вычислительные различия между CPU и GPU, обеспечивая одинаковые ключи для одного изображения. Без детерминизма эмбеддинги могут слегка отличаться, что приведёт к неверному ключу при расшифровке.


    Обработка изображения (process_image)
    Функция process_image загружает изображение и извлекает эмбеддинги из слоёв 4 и 16 модели YOLO11n-seg.

    Загрузка. Изображение (maryJane.png, 1088x1920) читается с помощью OpenCV и преобразуется в тензор [1, 3, 1088, 1920]. Размер 1088 кратен 32, так требует архитектура yolo.

    Извлечение активаций. Хуки (register_forward_hook) захватывают активации слоёв 4 и 16

    layers[4].register_forward_hook(get_activation("layer_4"))
    layers[16].register_forward_hook(get_activation("layer_16"))
    На выходе. Слой 4 - тензор [1, 128, 34, 60], слой 16 - [1, 64, 17, 30].

    Усреднение.

    Активации усредняются по высоте и ширине, давая 128 чисел (слой 4) и 64 числа (слой 16). В итоге 192 числа (float32, диапазон -10 до 10).

    Функция возвращает эмбеддинги, которые затем используются для генерации ключа.



    Генерация ключа и IV (generate_key_and_iv)
    Функция преобразует эмбеддинги в ключ (16 байт) и IV (16 байт) для AES-CBC.

    def generate_key_and_iv(embeddings):
    flat_embeddings = torch.cat([e.flatten() for e in embeddings]).cpu().numpy()
    flat_embeddings = np.round(flat_embeddings, decimals=4)
    hash_digest = hashlib.sha256(flat_embeddings.tobytes()).digest()
    return hash_digest[:16], hash_digest[16:32]
    Объединение.
    Эмбеддинги (128 + 64 числа) объединяются в массив из 192 чисел.

    Округление.
    Числа округляются до 4 знаков (decimals=4), чтобы устранить шум, сохраняя чувствительность к пикселям. Еще я это делал для того чтобы запустить на разных системах.

    Хеширование.
    Массив преобразуется в байты и хешируется через SHA-256, давая 32 байта. Первые 16 байт — ключ, следующие 16 — IV.
    SHA-256 обеспечивает уникальность хэша. Изменение одного пикселя меняет эмбеддинги.

    Шифрование (encrypt_data)
    Функция шифрует сообщение через AES-CBC.​
    def encrypt_data(data, key, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    ct_bytes = cipher.encrypt(pad(data, AES.block_size))
    return ct_bytes
    Вход. Сообщение ("doza_pidor".encode()), ключ и IV.
    Паддинг. Сообщение дополняется до кратности 16 байт.
    Шифрование. AES-CBC шифрует сообщение, используя ключ и IV
    Выход. "9c901f2b17cd0a91a9ef3995310db530"

    Используется то же самое изображение, модель ИИ и зашифрованное сообщение.

    import cv2
    import numpy as np
    import torch
    from ultralytics import YOLO
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import unpad
    import hashlib

    # Настройка детерминизма
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    torch.use_deterministic_algorithms(True)

    def generate_key_and_iv(embeddings):
    flat_embeddings = torch.cat([e.flatten() for e in embeddings]).cpu().numpy()
    flat_embeddings = np.round(flat_embeddings, decimals=4)
    hash_digest = hashlib.sha256(flat_embeddings.tobytes()).digest()
    return hash_digest[:16], hash_digest[16:32]

    def decrypt_data(ct_bytes, key, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    pt_bytes = unpad(cipher.decrypt(ct_bytes), AES.block_size)
    return pt_bytes

    def process_image(image_path, model):
    image = cv2.imread(image_path)
    if image is None:
    raise ValueError("Не удалось загрузить изображение!")
    original_shape = image.shape[:2]
    height, width = original_shape
    yolo_size = (max(32, (height + 31) // 32 * 32), max(32, (width + 31) // 32 * 32))
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.uint8)
    image_tensor = torch.from_numpy(image_rgb).permute(2, 0, 1).float() / 255.0
    image_tensor = image_tensor.clamp(0.0, 1.0).unsqueeze(0).to(model.device)
    activations = {}
    def get_activation(name):
    def hook(module, input, output):
    activations[name] = output
    return hook
    layers = model.model.model
    layers[4].register_forward_hook(get_activation("layer_4"))
    layers[16].register_forward_hook(get_activation("layer_16"))
    with torch.no_grad():
    results = model(image, conf=0.4, imgsz=yolo_size)
    embeddings = []
    for layer_name in ["layer_4", "layer_16"]:
    activation = activations.get(layer_name, torch.zeros(1))
    if len(activation.shape) == 4:
    embedding = activation.mean(dim=[2, 3])
    else:
    embedding = torch.zeros(1)
    embeddings.append(embedding)
    return embeddings

    # Основной код расшифровки
    device = torch.device("cpu")
    model = YOLO("yolo11n-seg.pt").to(device)
    image_path = "images/mary1_1_modified_10.png"
    ct_bytes = bytes.fromhex("9c901f2b17cd0a91a9ef3995310db530") # Замените на реальное значение

    # Расшифровка
    embeddings = process_image(image_path, model)
    key, iv = generate_key_and_iv(embeddings)
    decrypted_message = decrypt_data(ct_bytes, key, iv)
    print("Расшифрованное сообщение:", decrypted_message.decode())
    Настройка детерминизма
    Как и в шифровании, код начинается с настройки детерминизма PyTorch.

    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False
    torch.use_deterministic_algorithms(True)

    кто вообще эти статьи нахуй читает
    Это гарантирует, что эмбеддинги, полученные из изображения (maryJane.png), будут такими же, как при шифровании. Без детерминизма даже незначительные вычислительные различия при вычислениях на CPU и GPU дадут разные эмбеддинги, что приведёт к неверному ключу и провалу расшифровки.

    Обработка изображения (process_image)
    Функция process_image идентична той, что используется в шифровании. Она загружает изображение и извлекает эмбеддинги из слоёв 4 и 16 модели.

    layers[4].register_forward_hook(get_activation("layer_4"))
    layers[16].register_forward_hook(get_activation("layer_16"))
    Функция возвращает эмбеддинги, которые должны совпадать с теми, что использовались при шифровании, если изображение не изменилось.

    Генерация ключа и IV (generate_key_and_iv)
    Функция идентична шифрованию.

    def generate_key_and_iv(embeddings):
    flat_embeddings = torch.cat([e.flatten() for e in embeddings]).cpu().numpy()
    flat_embeddings = np.round(flat_embeddings, decimals=4)
    hash_digest = hashlib.sha256(flat_embeddings.tobytes()).digest()
    return hash_digest[:16], hash_digest[16:32]
    Расшифровка (decrypt_data)
    Функция восстанавливает сообщение через AES-CBC.
    def decrypt_data(ct_bytes, key, iv):
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    pt_bytes = unpad(cipher.decrypt(ct_bytes), AES.block_size)
    return pt_bytes
    Вход. Зашифрованное сообщение (например, 9c901f2b17cd0a91a9ef3995310db530), ключ и IV.
    Расшифровка. AES-CBC декодирует данные, используя ключ и IV, полученные от эмбеддингов.
    Удаление паддинга. Функция unpad убирает дополнение, добавленное при шифровании.
    Выход. Исходное сообщение. "doza_pidor"
     
    Этот материал оказался полезным?
    Вы можете отблагодарить автора темы путем перевода средств на баланс
    Отблагодарить автора
  2. value
    value 5 май 2025 бэкапы не помогут 366 6 янв 2022
    Паяльник vs шифрование на эмбеддингах
     
  3. Элейна
    Элейна 5 май 2025 4668 16 авг 2019
    Теперь амняму настолько сложно конфетку достать?
     
  4. Shamssy
    Shamssy 6 май 2025 291 9 июн 2022
    Прочитал и задался вопросом, нахуя я это читал ? Годная статья
     
  5. loosle
    loosle 12 май 2025 от 200.000₽ играя в CS — https://lolz.live/threads/8621957/ 412 3 янв 2024
    автор писал статью под дозой
     
  6. зайцевПлюсОдин
    Blya какой же ты еблан на дозе. Ты даже скопировать статьи нормально не можешь я хуею. В следуюший раз просто копируй не думая чтобы материал распространялся в нормальном виде.
     
    28 май 2025 Изменено
Top