Загрузка...

Break me if you can: encryption on embedding

Thread in Articles created by доза May 5, 2025. 495 views

  1. доза
    доза Topic starter May 5, 2025 Banned 397 Jul 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"
     
    This article was useful for you?
    You can thank the author of the topic by transferring funds to your balance
    Thank the author
  2. value
    value May 5, 2025 Синий экран 372 Jan 6, 2022
    Паяльник vs шифрование на эмбеддингах
     
  3. Элейна
    Элейна May 5, 2025 4660 Aug 16, 2019
    Теперь амняму настолько сложно конфетку достать?
     
  4. Shamssy
    Shamssy May 6, 2025 297 Jun 9, 2022
    Прочитал и задался вопросом, нахуя я это читал ? Годная статья
     
  5. loosle
    loosle May 12, 2025 :fap: => :muscle: 559 Jan 3, 2024
    автор писал статью под дозой
     
  6. зайцевПлюсОдин
    Blya какой же ты еблан на дозе. Ты даже скопировать статьи нормально не можешь я хуею. В следуюший раз просто копируй не думая чтобы материал распространялся в нормальном виде.
     
Loading...
Top