Внедряем бэкдор в RSA ключ
Здарова и с внеплановой пятницей!
Сегодня я покажу тебе как захуячить бэкдор в RSA ключ.
С чего все началось. Да блядь хуль мусолить, даж в официальных алгоритмах возможны бэкдоры.
Короче был такой алгоритм Dual_EC_DRBG стандартизованный национальным институтом стандартов и технологий пиндостана (NIST).
Прошу отметить, что предоставленная здесь информация предназначена исключительно для образовательных и информационных целей. Я не призываю и не одобряю незаконные действия, и использование этой информации для незаконных целей запрещено. Читатели должны соблюдать законы своей страны и использовать свои навыки с уважением к этическим нормам и законам.
Алгоритм использует эллиптические кривые, и изначально был принят как безопасный криптографический генератор случайных чисел. Однако... что-то пошло по пизде.
В 2007 году, любители покопаться в кишочках обнаружили в нем бэкдор.
Теоретически, если ты знаешь определённые параметры (точку
Q, связанную с другой точкойP), можно предсказать выход генератора — то есть знать, какие случайные числа он генерирует.
Получается не такой уж и случайный генератор чисел. За всем, как обычно, стояли хитрожопые АНБ с целью наебать всех. А дальше вылез Сноуден и всё это заапрувил. Вот это нихуясе!
А RSA Security использовало Dual_EC_DRBG по умолчанию. Причем АНБ забашляло 10кк баксов этой самой RSA Security за такую закладочку.
По итогу:
- NIST отозвал рекомендацию по Dual_EC_DRBG
 - RSA все прокляли и доверие к ним пропало
 
Ну дак вот. Как бы тебе не ссали в уши — никому не верь!
Таких историй было несколько, но не суть.
Если интересно можешь загуглить сам. Там чет еще про роутеры помню было, где можно было восстановить приватный ключ из публичного и расшифровывать траффик. Чето про тайваньские чипы в 2013 году. Похуй!
Внедряем бэкдор в RSA
Но вы тут не байки пришли слушать, а позырить как это на практике провернуть. Поехали.
Ниже я накидал код на python:
import hashlib
from Crypto.Util import number
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.backends import default_backend
import base64
# Хешируем строку в SHA256, интерпретируем как BigInteger
def hash_to_bigint(data: str) -> int:
    if not isinstance(data, str):
        raise ValueError("data must be a string")
    hash_hex = hashlib.sha256(data.encode()).hexdigest()
    return int('1' + hash_hex, 16)
# Следующее простое
def next_prime(n: int) -> int:
    if n % 2 == 0:
        n += 1
    while not number.isPrime(n):
        n += 2
    return n
# Генерация RSA ключей с "бэкдором"
def generate_backdoored_key(secret: str):
    # Увеличиваем размер числа перед поиском простого
    p = next_prime(hash_to_bigint(secret + 'A') << 1024)
    q = next_prime(hash_to_bigint(secret + 'B') << 1024)
    n = p * q
    phi = (p - 1) * (q - 1)
    e = 65537
    d = pow(e, -1, phi)
    private_numbers = rsa.RSAPrivateNumbers(
        p=p,
        q=q,
        d=d,
        dmp1=d % (p - 1),
        dmq1=d % (q - 1),
        iqmp=pow(q, -1, p),
        public_numbers=rsa.RSAPublicNumbers(e=e, n=n)
    )
    private_key = private_numbers.private_key(backend=default_backend())
    public_key = private_key.public_key()
    pem_private = private_key.private_bytes(
        serialization.Encoding.PEM,
        serialization.PrivateFormat.TraditionalOpenSSL,
        serialization.NoEncryption()
    )
    pem_public = public_key.public_bytes(
        serialization.Encoding.PEM,
        serialization.PublicFormat.SubjectPublicKeyInfo
    )
    return pem_public.decode(), pem_private.decode()
# Восстановление приватного ключа по секрету и открытому ключу
def restore_private_key(secret: str, pem_public: str):
    public_key = serialization.load_pem_public_key(
        pem_public.encode(), backend=default_backend()
    )
    numbers = public_key.public_numbers()
    n = numbers.n
    e = numbers.e
    p = next_prime(hash_to_bigint(secret + 'A') << 1024)
    q = next_prime(hash_to_bigint(secret + 'B') << 1024)
    phi = (p - 1) * (q - 1)
    d = pow(e, -1, phi)
    private_numbers = rsa.RSAPrivateNumbers(
        p=p,
        q=q,
        d=d,
        dmp1=d % (p - 1),
        dmq1=d % (q - 1),
        iqmp=pow(q, -1, p),
        public_numbers=rsa.RSAPublicNumbers(e=e, n=n)
    )
    private_key = private_numbers.private_key(backend=default_backend())
    return private_key.private_bytes(
        serialization.Encoding.PEM,
        serialization.PrivateFormat.TraditionalOpenSSL,
        serialization.NoEncryption()
    ).decode()
# Демонстрация
secret = 'my-bashdays-secret'
pem_public, pem_private = generate_backdoored_key(secret)
print('--- PUBLIC KEY PEM ---')
print(pem_public)
# Шифрование
message = b'Hello, Bashdays world!'
public_key = serialization.load_pem_public_key(pem_public.encode(), backend=default_backend())
ciphertext = public_key.encrypt(
    message,
    padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
)
cipher_b64 = base64.b64encode(ciphertext).decode()
print('Encrypted (base64):', cipher_b64)
# Восстановление приватного ключа
pem_restored_private = restore_private_key(secret, pem_public)
print('--- RESTORED PRIVATE KEY PEM ---')
print(pem_restored_private)
# Расшифровка
private_key = serialization.load_pem_private_key(pem_restored_private.encode(), password=None, backend=default_backend())
decrypted = private_key.decrypt(
    base64.b64decode(cipher_b64),
    padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
)
print('Decrypted message:', decrypted.decode())
Если его запустить, он наглядно продемонстрирует всю подноготную.
Что делает этот скрипт
- Создаёт RSA-ключи, которые можно восстановить из секрета (это и есть бэкдор).
 - Шифрует сообщение открытым ключом.
 - Восстанавливает закрытый ключ без сохранения — только из секрета и публичного ключа.
 - Расшифровывает сообщение этим восстановленным ключом.
 
Почему можно восстановить закрытый ключ, если знаешь секрет:
Если ты можешь восстановить те же p и q, то:
- Ты можешь пересчитать 
n = p * q— он должен совпасть сnв публичном ключе. - Посчитать 
φ(n) = (p - 1)(q - 1) - Получить 
eиз публичного ключа (он в нём явно хранится) - Вычислить 
d = e⁻¹ mod φ(n) - Собрать весь приватный ключ
 
Смысл бэкдора
Секрет — это не просто строка, это способ воспроизводимо получить p и q. Ты как будто заранее знаешь, из чего они были сгенерированы.
Вот и вся наука! Изучай!